ES6、ES7、ES8特性

Updated on with 174 views

ES6

ES7

ES8

## a 对熟悉Java,object-c,c#等纯面向对象语言的开发者来说,都会对class有一种特殊的情怀。ES6 引入了 `class`(类),让JavaScript的面向对象编程变得更加简单和易于理解。
class Animal {
    // 构造函数,实例化的时候将会被调用,如果不指定,那么会有一个不带参数的默认构造函数.
    constructor(name,color) {
      this.name = name;
      this.color = color;
    }
    // toString 是原型对象上的属性
    toString() {
      console.log('name:' + this.name + ',color:' + this.color);
    }
  }

 var animal = new Animal('dog','white');//实例化Animal
 animal.toString();

继承

class Cat extends Animal {
  constructor(action) {
    // 子类必须要在constructor中指定super 函数,否则在新建实例的时候会报错.
    // 如果没有置顶consructor,默认带super函数的constructor将会被添加、
    super('cat','white');
    this.action = action;
  }
  toString() {
    console.log(super.toString());
  }
 }

 var cat = new Cat('catch')
 cat.toString();

 console.log(cat instanceof Cat); // true
 console.log(cat instanceof Animal); // true

class的本质,由下可以发现class的本质还是一个函数,class的相关语法及继承,也是原型链的语法糖表现形式。

 console.log(type of Animal) // function
 console.log(Animal) //可以发现在Animal中定义的constructor和toString都在Animal的prototype中
 console.log(animal.hasOwnProperty('name')); //true
 console.log(animal.hasOwnProperty('toString')); // false
 console.log(animal.__proto__.hasOwnProperty('toString')); // true

模块化

导出export 与 导入import

导出导入变量常量

export var name = 'Rainbow'
export const sqrt = Math.sqrt

import {name} from "./test.js"
import {sqrt} from "./test.js"

导出导入多个变量

var name = 'Rainbow';
var age = '24';
export {name, age};

import {name, age} from "./test.js"

导出导入函数

export function myfn(someArg) {
  return someArg;
}

import {myfn} from "./test.js"
myfn("arg")

导出重命名

export {
    myName as name,
    myAge as age,
    myfn as fn
}
import {name, age, fn} from "./test.js"

导入重命名

import { myName as name, myAge as age} from "./test.js"

直接导入整个模块

import * as info from "./test.js";//通过*来批量接收,as 来指定接收的名字
console.log(info.myfn());
console.log(info.myAge);
console.log(info.myName);

默认导出

//一个模块只能有一个默认导出,对于默认导出,导入的名称可以和导出的名称不一致
export default function() {
    return "默认导出一个方法"
}
import myFn from "./test.js";//注意这里默认导出不需要用{}。
console.log(myFn());//默认导出一个方法

//可以将所有需要导出的变量放入一个对象中,然后通过export default进行导出
export default {
    myFn() {
        return "默认导出一个方法"
    },
    myName:"laowang"
}
import myObj from "./test.js";
console.log(myObj.myFn(), myObj.myName);//默认导出一个方法 laowang

//同样也支持混合导出
export default function() {
    return "默认导出一个方法"
}
export var myName="laowang";
import myFn, {myName} from "./test.js";
console.log(myFn(),myName);//默认导出一个方法 laowang

箭头函数

箭头函数就是函数的一种简写形式,使用括号包裹参数,跟随一个 =>,紧接着是函数体;

三个特点

  • 不需要function 关键字来创建函数
  • 箭头之后可以直接是一个表达式,或者是大括号括起的函数体
  • 继承当前上下文的 this关键字

函数参数默认值

ES6支持在定义函数的时候为其设置默认值
// ES6;
function foo(height = 50, color = 'red') {
    console.log("height:" + height + ", color:" + color);
}

foo(30, 'blue'); // height:30, color:blue
foo();// height:50, color:red

ES6之前,当未传入参数时

function foo(height, color) {
    var height = height || 50;
    var color = color || 'red';
    console.log("height:" + height + ", color:" + color);
}

这样写一般没问题,但当参数的布尔值为false时,就会有问题了。比如,我们这样调用foo函数:

foo(0, "")

因为0的布尔值为false,这样height的取值将是50。同理color的取值为red

所以说,函数参数默认值不仅能是代码变得更加简洁而且能规避一些问题。

模板字符串

ES6支持模板字符串,使得字符串的拼接更加的简洁、直观。

在ES6中通过${}就可以完成字符串的拼接,只需要将变量放在大括号之中。

不使用模板字符串:

var name = 'Your name is ' + first + ' ' + last + '.'

使用模板字符串:

var name = `Your name is ${first} ${last}.`

解构赋值

解构赋值语法是JavaScript的一种表达式,可以方便的从数组或者对象中快速提取值赋给定义的变量。

获取数组中的值

从数组中获取值并赋值到变量中,变量的顺序与数组中对象顺序对应。

var foo = ["one", "two", "three", "four"];

var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"

//如果你要忽略某些值,你可以按照下面的写法获取你想要的值
var [first, , , last] = foo;
console.log(first); // "one"
console.log(last); // "four"

//你也可以这样写
var a, b; //先声明变量

[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2

如果没有从数组中的获取到值,你可以为变量设置一个默认值。

var a, b;

[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7

交换变量的值

var a = 1;
var b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

获取对象中的值

const student = {
  name:'Ming',
  age:'18',
  city:'Shanghai'
};

const {name, age, city} = student;
console.log(name); // "Ming"
console.log(age); // "18"
console.log(city); // "Shanghai" 延展操作符

Spread/Rest操作符

Spread/Rest...可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开或者将传入参数合并;还可以在构造对象时, 将对象表达式按key-value的方式展开。

函数调用时使用Spread操作符

function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];

//使用延展操作符
console.log(sum(...numbers)); // 6

函数传参时使用Rest操作符

function foo(...args) {
  console.log(args);
}
foo( 1, 2, 3, 4, 5);

数组、对象拷贝

var arr = [1, 2, 3];
var arr2 = [...arr];

var obj1 = { foo: 'bar', x: 42 };
var clonedObj = { ...obj1 };

连接多个数组

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];// 将 arr2 中所有元素附加到 arr1 后面并返回
//等同于
var arr3 = arr1.concat(arr2);

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var mergedObj = { ...obj1, ...obj2 };

对象属性简写

当属性的对象命名和值的变量命名一致时,可以进行简写
const name='Ming',age='18',city='Shanghai';
const student = {
    name,
    age,
    city
};
console.log(student);//{name: "Ming", age: "18", city: "Shanghai"}

Promise

Promise 是异步编程的一种解决方案,比传统的解决方案callback更加的优雅。它最早由社区提出和实现的,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
// 不使用ES6
setTimeout(function()
{
    console.log('Hello'); // 1秒后输出"Hello"
    setTimeout(function()
    {
        console.log('Hi'); // 2秒后输出"Hi"
    }, 1000);
}, 1000);

//使用ES6
var waitSecond = new Promise(function(resolve, reject)
{
    setTimeout(resolve, 1000);
});

waitSecond
    .then(function()
    {
        console.log("Hello"); // 1秒后输出"Hello"
        return waitSecond;
    })
    .then(function()
    {
        console.log("Hi"); // 2秒后输出"Hi"
    });

上面的的代码使用两个then来进行异步编程串行化,避免了回调地狱:

Let与Const

ES6推荐使用let声明局部变量,相比之前的var(无论声明在何处,都会被视为声明在函数的最顶部)

let和var声明的区别:

var x = '全局变量';
{
  let x = '局部变量';
  console.log(x); // 局部变量
}
console.log(x); // 全局变量

let表示声明变量,而const表示声明常量,两者都为块级作用域;const 声明的变量都会被认为是常量,意思就是它的值被设置完成后就不能再修改了

const a = 1
a = 0 //报错

如果const的是一个对象,对象所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的地址没有变就行:

const student = { name: 'cc' }

student.name = 'yy';// 不报错
student  = { name: 'yy' };// 报错

Array.prototype.includes()

includes() 函数用来判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回false

arr.includes(x)
//等价于
arr.indexOf(x) >= 0

指数操作符

console.log(2**10)
//等价于
console.log(Math.pow(2, 10));

async/await

在ES8中加入了对async/await的支持,也就我们所说的异步函数,这是一个很实用的功能。 async/await将我们从头痛的回调地狱中解脱出来了,使整个代码看起来很简洁。

async doLogin2(userName) {
    const userId = await this.login(userName);
    const result = await this.getData(userId);
}

使用Promise.all进行并发处理

async function charCountAdd(data1, data2) {
    const [d1, d2] = await Promise.all([charCount(data1), charCount(data2)]);
    return d1 + d2;
}
charCountAdd('Hello', 'Hi').then(console.log);
function charCount(data) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(data.length);
        }, 1000);
    });
}

捕捉整个async/await函数的错误

async function charCountAdd(data1, data2) {
    const d1 = await charCount(data1);
    const d2 = await charCount(data2);
    return d1 + d2;
}
charCountAdd('Hello','Hi')
    .then(console.log)
    .catch(e => console.log); //捕捉整个async/await函数的错误

捕捉单个的await表达式的错误

async function charCountAdd(data1, data2) {
    const d1 = await charCount(data1)
        .catch(e => console.log('d1 is null'));
    const d2 = await charCount(data2)
        .catch(e => console.log('d2 is null'));
    return d1 + d2;
}
charCountAdd('Hello','Hi').then(console.log);

Object.values()

Object.values()是一个与Object.keys()类似的新函数,但返回的是Object自身属性的所有值,不包括继承的值。

//假设我们要遍历如下对象obj的所有值
const obj = {a: 1, b: 2, c: 3};
//不使用Object.values() :ES7
const vals = Object.keys(obj).map(key => obj[key]);
console.log(vals);//[1, 2, 3]
//使用Object.values() :ES8
const values = Object.values(obj1);
console.log(values);//[1, 2, 3]

Object.entries()

Object.entries()函数返回一个给定对象自身可枚举属性的键值对的数组。

//假设我们要遍历如下对象obj的所有属性的key和value
const obj = {a: 1, b: 2, c: 3};
//不使用Object.entries() :ES7
Object.keys(obj).forEach(key=>{
 console.log(`key: ${key} value:${obj[key]}`);
})
//使用Object.entries() :ES8
for(let [key, value] of Object.entries(obj)){
 console.log(`key: ${key} value:${value}`)
}

String padding

在ES8中String新增了两个实例函数String.prototype.padStartString.prototype.padEnd,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。

console.log('0.0'.padStart(4,'10')) //10.0
console.log('0.00'.padStart(20))//                0.00 常用于右对齐格式化

console.log('0.0'.padEnd(4,'0')) //0.00
console.log('0.0'.padEnd(10,'0'))//0.00000000

函数参数列表结尾允许逗号

var f = function(a, b,) {
 ...
}

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors() 函数用来获取一个对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。

const obj2 = {
 name: 'Jine',
 get age() { return '18' }
};
Object.getOwnPropertyDescriptors(obj2)
// {
//   age: {
//     configurable: true,
//     enumerable: true,
//     get: function age(){}, //the getter function
//     set: undefined
//   },
//   name: {
//     configurable: true,
//     enumerable: true,
//   value:"Jine",
//   writable:true
//   }
// }

参考


标题:ES6、ES7、ES8特性
作者:SunnySky
地址:https://www.tianyang.pub/articles/2019/10/14/1571065927800.html

Responses