原文地址:ES6、ES7、ES8特性一锅炖(ES6、ES7、ES8学习指南) 这里作学习笔记
ES6 新特性
- let 与 const
- 箭头函数
- 类
- 模块化
- 模板字符串
- 解构赋值
- 延展操作符
- Promise
- 函数参数默认值
- 对象属性简写
1. let 与 const
在之前JS是没有块级作用域的,const与let填补了这方便的空白,const与let都是块级作用域
使用 var 定义的变量为函数级作用域:
{
var a = 10;
}
console.log(a); // 输出10
复制代码
使用 let 与 const 定义的变量为块级作用域:
{
let a = 10;
}
console.log(a); //-1 or Error“ReferenceError: a is not defined”
复制代码
2. 箭头函数
详见 JavaScript系列 — 普通函数、箭头函数、构造函数的区别及其对应 this 指向
3. 类(class)
对熟悉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();
console.log(animal.hasOwnProperty('name')); //true
console.log(animal.hasOwnProperty('toString')); // false
console.log(animal.__proto__.hasOwnProperty('toString')); // true
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();
// 实例cat 是 Cat 和 Animal 的实例,和Es5完全一致。
console.log(cat instanceof Cat); // true
console.log(cat instanceof Animal); // true
复制代码
4. 模块化
ES5不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,通过import来引用其它模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。
导出(export)
ES6允许在一个模块中使用export来导出多个变量或函数。
导出变量
//test.js
export var name = 'Rainbow'
复制代码
ES6不仅支持变量的导出,也支持常量的导出。
export const sqrt = Math.sqrt;
// 导出常量
ES6将一个文件视为一个模块,上面的模块通过 export 向外输出了一个变量。一个模块也可以同时往外面输出多个变量。
//test.js
var name = 'Rainbow';
var age = '24';
export {name, age};
复制代码
导出函数
// myModule.js
export function myModule(someArg) {
return someArg;
}
复制代码
导入(import)
定义好模块的输出以后就可以在另外一个模块通过import引用。
import {myModule} from 'myModule'; // main.js
import {name,age} from 'test'; // test.js
复制代码
一条import 语句可以同时导入默认函数和其它变量。
import defaultMethod, { otherMethod } from 'xxx.js';
5. 模板字符串
ES6支持模板字符串,使得字符串的拼接更加的简洁、直观
- 不使用模板字符串
var name = 'Your name is ' + first + ' ' + last + '.'
复制代码
- 使用模板字符串
var name = `Your name is ${first} ${last}.`
复制代码
6. 解构赋值
解构赋值语法是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"
复制代码
7. 延展操作符(…)
延展操作符...
可以在函数调用/数组构造时, 将数组表达式或者 string 在语法层面展开;还可以在构造对象时, 将对象表达式按 key-value 的方式展开
语法
- 函数调用
myFunction(...iterableObj);
复制代码
- 数组构造或字符串
[...iterableObj, '4', ...'hello', 6];
复制代码
- 构造对象时,进行克隆或者属性拷贝
let objClone = { ...obj };
复制代码
应用场景
- 在函数调用时使用延展操作符(最常用:函数外不用一个一个传,直接整体传,函数内会将其一个一个拆开)
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
//不使用延展操作符
console.log(sum.apply(null, numbers));
//使用延展操作符
console.log(sum(...numbers)); // 6
复制代码
- 构造数组
没有展开语法的时候,只能组合使用 push,splice,concat 等方法,来将已有数组元素变成新数组的一部分。有了展开语法, 构造新数组会变得更简单、更优雅:
const stuendts = ['Jine','Tom'];
const persons = ['Tony',... stuendts,'Aaron','Anna'];
conslog.log(persions)// ["Tony", "Jine", "Tom", "Aaron", "Anna"]
复制代码
- 数组拷贝
var arr = [1, 2, 3];
var arr2 = [...arr]; // 等同于 arr.slice()
arr2.push(4);
console.log(arr2)//[1, 2, 3, 4]
复制代码
- 连接多个数组
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];// 将 arr2 中所有元素附加到 arr1 后面并返回
//等同于
var arr4 = arr1.concat(arr2);
复制代码
8. Promise
详细见 JavaScript系列 — Promise、Generator、async及await
9. 对象属性简写
在ES6中允许我们在设置一个对象的属性的时候不指定属性名
- 不使用 ES6
const name='Ming',age='18',city='Shanghai';
const student = {
name:name,
age:age,
city:city
};
console.log(student);//{name: "Ming", age: "18", city: "Shanghai"}
复制代码
- 使用 ES6
const name='Ming',age='18',city='Shanghai';
const student = {
name,
age,
city
};
console.log(student);//{name: "Ming", age: "18", city: "Shanghai"}
复制代码
10. 函数参数默认值
ES6支持在定义函数的时候为其设置默认值:
function foo(height = 50, color = 'red')
{
// ...
}
复制代码
- 不使用 ES6 设置默认值:
function foo(height, color)
{
var height = height || 50;
var color = color || 'red';
//...
}
复制代码
这样写一般没问题,但当参数的布尔值为false时,就会有问题了。比如,我们这样调用foo函数:
foo(0, "")
复制代码
因为 0 的布尔值为 false
,这样 height 的取值将是 50
。同理 color 的取值为 red
。
所以说,函数参数默认值不仅能是代码变得更加简洁而且能规避一些问题。
ES7 新特性
- 数组的 includes() 方法
- 指数操作符
1. Array.prototype.includes()
includes() 函数用来判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回false。
includes 函数与 indexOf 函数很相似,下面两个表达式是等价的:
arr.includes(x)
arr.indexOf(x) >= 0
复制代码
接下来我们来判断数字中是否包含某个元素:
- ES7 之前的做法
使用indexOf()
验证数组中是否存在某个元素,这时需要根据返回值是否为-1
来判断:
let arr = ['react', 'angular', 'vue'];
if (arr.indexOf('react') !== -1)
{
console.log('react存在');
}
复制代码
- 使用 ES7 的 includes() 方法
let arr = ['react', 'angular', 'vue'];
if (arr.includes('react'))
{
console.log('react存在');
}
// 使用includes()验证数组中是否存在某个元素,这样更加直观简单
复制代码
2. 指数操作符(2**5 === 32)
在ES7中引入了指数运算符**
,**
具有与Math.pow(..)
等效的计算结果
- 不使用指数操作符
// 使用自定义的递归函数calculateExponent或者Math.pow()进行指数运算
function calculateExponent(base, exponent)
{
if (exponent === 1)
{
return base;
}
else
{
return base * calculateExponent(base, exponent - 1);
}
}
console.log(calculateExponent(2, 10)); // 输出1024
console.log(Math.pow(2, 10)); // 输出1024
复制代码
- 使用指数操作符
使用指数运算符**,就像+、-等操作符一样:
console.log(2**10);// 输出1024
复制代码
ES8 新特性
- async/await
- Object.values()
- Object.entries()
- Object.getOwnPropertyDescriptors()
- padStart、padEnd
- 函数参数列表结尾允许逗号
1. async/await
详细见 JavaScript系列 — Promise、Generator、async及await
2. 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.values()为我们省去了遍历key,并根据这些key获取value的步骤
3. Object.entries
Object.entries()函数返回一个给定对象自身可枚举属性的键值对的数组。
接下来我们来遍历上文中的obj对象的所有属性的key和value:
- 不使用Object.entries() :ES7
Object.keys(obj).forEach(key=>{
console.log('key:'+key+' value:'+obj[key]);
})
//key:a value:1
//key:b value:2
//key:c value:3
复制代码
- 使用Object.entries() :ES8
for(let [key,value] of Object.entries(obj1)){
console.log(`key: ${key} value:${value}`)
}
//key:a value:1
//key:b value:2
//key:c value:3
复制代码
3. Object.getOwnPropertyDescriptors()
返回obj对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象
const obj2 = {
name: 'Jine',
get age() { return '18' }
};
Object.getOwnPropertyDescriptors(obj2)
复制代码
4. padStart、padEnd
str.padStart(targetLength,[padString])
- targetLength:当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
- padString:(可选)填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断,此参数的缺省值为 ” “
console.log('0.0'.padStart(4,'10')) // 10.0
console.log('0.0'.padStart(20)) // 0.00
复制代码
str.padEnd(targetLength,[padString])
- targetLength:当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
- padString:(可选) 填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断,此参数的缺省值为 ” “
console.log('0.0'.padEnd(4,'0')) // 0.00
console.log('0.0'.padEnd(10,'0')) // 0.00000000
复制代码