目录
- 1. ECMASript 6(2015)
- 1.1 let 关键字
- 1.2 const关键字
- 1.3 变量的解构赋值
- 1.4 模板字符串
- 1.5 简化对象的写法
- 1.6 箭头函数
- 1.7 rest参数
- 1.8 spread 扩展运算符
- 1.9 Symbol
- 1.10 迭代器
- 1.11 生成器
- 1.12 Promise
- 1.13 Set
- 1.14 Map
- 1.15 class类
- 1.16 数值扩展
- 1.17 对象扩展
- 1.18 模块化
- 1.19 函数参数默认值
- 2. ECMASript 7(2016)
- 2.1 Array.prototype.includes
- 2.2 指数操作符
- 3. ECMASript 8(2017)
- 3.1 async和await
- 3.2 Object.values 和 Object.entries
- 3.3 Object.getOwnPropertyDescriptors
- 3.4 String padding
- 4. ECMASript 9(2018)
- 4.1 Rest/Spread 属性
- 4.2 Promise.finally()
- 4.3 正则表达式命名捕获组
- 4.4 正则表达式反向断言
- 4.5 正则表达式的dotAll模式
- 5. ECMASript 10(2019)
- 5.1 flat()、flatMap()
- 5.2 trimStart()、trimEnd()
- 5.3 Object.fromEntries()
- 5.4 Function.prototype.toString()
- 5.5 基本数据类型BigInt
前言:用此篇文章来记录一下常用的ES6-10的新增知识。
1. ECMASript 6(2015)
1.1 let 关键字
let关键字用来声明变量,使用let声明的变量有以下特点:
- 不允许重复声明
- 块级作用域
- 不允许变量提升
- 不影响作用域链
1.2 const关键字
const关键字用来声明变量,const声明有以下特点:
- 声明变量必须赋初始值
- 标识符一般大小
- 不允许重复声明
- 值不允许修改
- 块级作用域
注意:对象属性修改和数组元素修改不会发生const错误
使用场景:声明对象类型使用const,声明非对象属性使用let
1.3 变量的解构赋值
ES6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
//数组的解构赋值
const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;
//对象的解构赋值
const lin = {
name: '林志颖',
tags: ['车手', '歌手', '小旋风', '演员']
};
let {name, tags} = lin;
使用场景:频繁使用对象方法、数组元素,就可以使用解构赋值。
1.4 模板字符串
模板字符串是增强版的字符串,使用反引号(`)进行表示,特点如下:
- 字符串中可以出现换行符
- 可以使用
${ XXX}
形式输出变量
使用场景:当遇到字符串与变量拼接的情况使用模板字符串
1.5 简化对象的写法
ES6允许大括号里面,直接写入变量和函数,作为对象的属性和方法。
let name = "hello"
let fn = function(){}
let obj = {
name,
fn
}
使用场景:对象简写的形式简化了代码,所以能简写的最好简写
1.6 箭头函数
ES6允许使用箭头来定义函数。使用箭头函数需要注意以下几点:
- 如果参数只有一个,则小括号可以省略
- 如果函数体只有一条语句,则大括号可以省略,函数的返回值就是该语句的执行结果
- 箭头函数本身没有this,它的this执行它所在的作用域下的this值
- 箭头函数不能作为构造函数进行实例化
- 不能使用arguments
使用场景:箭头函数不能改变this的指向,适合用来指定回调函数
1.7 rest参数
ES6引入了rest参数,用于获取函数的实参,用来代替arguments
需要注意,rest参数必须是最后一个形参。
rest参数可以用以下用途:
- 当参数个数不确定时
function rest(...arr) {
for (let item of arr) {
console.log(item);
}
}
rest(1, 3, 5);
- 当参数个数不确定时,已知某些参数
function rest02(item, ...arr) {
console.log(item); // 1
console.log(arr); // [2, 3]
}
rest02(1, 2, 3);
- 进行解构赋值
var [a,...temp]=[1, 2, 3];
console.log(a); // 1
console.log(temp); // [2,3]
1.8 spread 扩展运算符
扩展运算符:...
它就像是rest参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
spread 扩展运算符可以有以下用途:
- 将数组转化为用逗号分隔的参数序列
function test(a,b,c){
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
}
var arr = [1, 2, 3];
test(...arr);
- 将一个数组拼接到另一个数组
var arr1 = [1, 2, 3,4];
var arr2 = [...arr1, 4, 5, 6];
console.log(arr2); // [1, 2, 3, 4, 4, 5, 6]
- 将字符串转为逗号分隔的数组
var str='JavaScript';
var arr= [...str];
console.log(arr); // ["J", "a", "v", "a", "S", "c", "r", "i", "p", "t"]
1.9 Symbol
ES6中引入了一个新的基本数据类型Symbol,表示独一无二的值。它是一种类似于字符串的数据类型,它的特点如下:
- Symbol的值是唯一的,用来解决命名冲突的问题
- Symbol值不能与其他类型数据进行运算
- Symbol定义的对象属性不能使用
for...in
遍历循环,但是可以使用Reflect.ownKeys
来获取对象的所有键名
let s1 = Symbol();
console.log(typeof s1); // "symbol"
let s2 = Symbol('hello');
let s3 = Symbol('hello');
console.log(s2 === s3); // false
使用场景:遇到唯一性的场景时可能会使用到Symbol
除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法,会在特定的情况下使用:
Symbol方法 | 解释 |
Symbol.hasInstance | 当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法 |
Symbol.isConcatSpreadable | 对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。 |
Symbol.species | 创建衍生对象时,会使用该属性 |
Symbol.match | 当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。 |
Symbol.replace | 当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值。 |
Symbol.search | 当该对象被 str.search (myObject)方法调用时,会返回该方法的返回值。 |
Symbol.split | 当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值。 |
Symbol.iterator | 对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍器 |
Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。 |
Symbol. toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返回值 |
Symbol. unscopables | 该对象指定了使用 with 关键字时,哪些属性会被 with环境排除 |
1.10 迭代器
迭代器(Iterator)实际上就是一种机制。它就是一个接口,为不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作。
(1) ES6 创造了一种新的遍历命令 for...of
循环,Iterator 接口主要供 for...of
消费
(2)迭代器原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的
next
方法,指针自动指向数据结构的第一个成员 - 接下来不点调用
next
方法,指针一直往后移动,直到指向最后一个成员 - 每次调用next方法返回一个包含
value
和done
属性的对象
//通过 Symbol.iterator 创建一个迭代器
const items = ["zero", "one", "two"];
const it = items[Symbol.iterator]();
it.next(); // {value: "zero", done: false}
it.next(); // {value: "one", done: false}
it.next(); // {value: "two", done: false}
it.next(); // {value: undefined, done: true}
(3)原生具备 iterator 接口的数据(可用 for of 遍历)
- Array、TypedArray
for (let item of ["zero", "one", "two"]) {
console.log(item); // zero one two
}
- Arguments
function args() {
for (let item of arguments) {
console.log(item); // zero one
}
}
args("zero", "one");
- Set
Set 是对其元素进行迭代,迭代的顺序与其添加的顺序相同
const set = new Set();
set.add("zero");
set.add("one");
for (let item of set) {
console.log(item); // zero one
}
- Map
Map 主要是迭代它们的 entries ,每个 entry 都会被编码为 [key, value] 的项, entries 是以确定的形式进行迭代,其顺序是与添加的顺序相同
const map = new Map();
map.set(0, "zero");
map.set(1, "one");
for (let item of map) {
console.log(item); // [0, "zero"] [1, "one"]
}
- String
字符串是可迭代的,但他们遍历的是 Unicode 码,每个码可能包含一个到两个的 Javascript 字符。
for (const c of 'z\uD83D\uDC0A') {
console.log(c);
}
1.11 生成器
生成器函数是ES6提供的一种异步编程的解决方法,语法与传统函数完全不一样:
function * gen(){
yield 'hello';
yield 'world';
return 'JavaScript';
}
let iterator = gen();
console.log(iterator)
console.log(iterator.next()); // {value: "hello", done: false}
console.log(iterator.next()); // {value: "world", done: false}
console.log(iterator.next()); // {value: "JavaScript", done: true}
需要注意:
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的
next
方法可以得到yield
后面的值 -
yield
相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次next
方法,执行一段代码 -
next
方法可以传递实参,这个参数会作为上一条执行的yield
语句的返回值
1.12 Promise
Promise是ES6引入的异步编程的新的解决方案,在语法上,Promise是一个构造函数,用来封装异步操作可以获取其成功或失败的结果
- Promise的构造函数:
Promise(excutor){}
-
Promise.prototype.then
方法 -
Promise.prototype.catch
方法
相关知识:《异步编程:Promise基础》
1.13 Set
ES6提供了新的数据结构Set(集合)。它类似于数组,但是成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和 for…of… 进行遍历。
Set的属性和方法:
属性和方法 | 简介 |
size | 返回集合的元素个数 |
add | 增加一个新的元素,返回当前的集合 |
delete | 删除元素,返回布尔值 |
has | 检查集合中是否包含某元素,返回布尔值 |
clear | 清空集合,返回undefined |
//创建一个空集合
let s = new Set();
//创建一个非空集合
let s1 = new Set([1,2,3,1,2,3]);
//返回集合的元素个数
console.log(s1.size); // 3
//添加新元素
console.log(s1.add(4)); // {1,2,3,4}
//删除元素
console.log(s1.delete(1)); //true
//检测是否存在某个值
console.log(s1.has(2)); // true
//清空集合
console.log(s1.clear()); //undefined
1.14 Map
ES6提供了Map数据结构,它类似于对象,也是键值队的集合,但是它的key值不限于字符串,可以是任何类型的值,Map也实现了iterator接口,所以可以使用扩展运算符和 for…of… 进行遍历。
Map的属性和方法:
属性和方法 | 简介 |
size | 返回Map的元素个数 |
set | 增加一个新的元素,返回当前的Map |
get | 返回键名对象的键值 |
has | 检查Map中是否包含某元素,返回布尔值 |
clear | 清空Map,返回undefined |
//创建一个空 map
let m = new Map();
//创建一个非空 map
let m2 = new Map([
['name', 'hello'],
]);
//获取映射元素的个数
console.log(m2.size); // 1
//添加映射值
console.log(m2.set('age', 6)); // {"name" => "hello", "age" => 6}
//获取映射值
console.log(m2.get('age')); // 6
//检测是否有该映射
console.log(m2.has('age')); // true
//清除
console.log(m2.clear()); // undefined
1.15 class类
ES6引入了类的概念,来作为对象的模板。通过class关键字可以定义类。ES6的class可以看做是一个语法糖,他的多数功能在ES5中也可以实现,新的class写法只是让对象原型的写法更加清晰,更像面向对象的编程语法。
class相关知识点:
- class: 声明类
- constructor :定义构造函数初始化
- extends :继承父类
- super :调用父级的方法
- static :定义静态的属性和方法
- 父类的方法可以重写
// 父类
class Phone {
//构造方法
constructor(brand, color, price) {
this.brand = brand;
this.color = color;
this.price = price;
}
//对象方法
call() {
console.log('打电话!')
}
}
//子类
class SmartPhone extends Phone {
constructor(brand, color, price, screen) {
super(brand, color, price);
this.screen = screen;
}
//子类方法
photo(){
console.log('可以拍照!');
}
//方法重写
call(){
console.log('视频通话!');
}
//静态方法
static run(){
console.log('运行程序')
}
}
//实例化对象
const Nokia = new Phone('诺基亚', '灰色', 230);
const iPhone = new SmartPhone('苹果', '白色', 6088, '5inch');
//调用子类方法
iPhone.photo();
//调用重写方法
iPhone.call();
//调用静态方法
SmartPhone.run();
1.16 数值扩展
ES6提供了二进制和八进制数值的新的写法,分别使用前缀0b
和0o
表示。
还提供了一个关于数值的方法:
方法 | 简介 |
Number.isFinite() | 用来检查一个数值是否为有限的 |
Number.isNaN() | 用来检查一个值是否为 NaN |
Number.parseInt() | 将全局方法 |
Number.parseFloat() | 将全局方法 |
Math.trunc | 用于去除一个数的小数部分,返回整数部分 |
Number.isInteger() | 用来判断一个数值是否为整数 |
1.17 对象扩展
ES6新增了一些Object对象的方法:
- Object.is():用来比较两个值是否严格相等,与===的行为基本一致,用法:
Object.is(value1, value2)
- Object.assign():对象的合并,将源对象的所有可枚举属性,复制到目标对象,返回目标对象,用法:
Object.assign(target, ...sources)
-
__proto__
、setPrototypeOf
可以直接设置对象的原型
1.18 模块化
使用模块化可以防止命名冲突、提高代码复用率、便于后期的维护。
ES6中的模块功能主要由两个命令构成:export 和 import
- export 命令:用于规定模块的对外接口
- import 命令:用于输入其他模块提供的功能
1.19 函数参数默认值
ES6支持在定义函数的时候为其设置默认值:
function foo(a = 1, b = 'hello')
{
// ...
}
2. ECMASript 7(2016)
2.1 Array.prototype.includes
Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值
语法如下:
- arr.includes(searchElement)
- arr.includes(searchElement, fromIndex)
参数其中:
-
arr
是被检测的数组 -
searchElement
是被检测的某个数据 -
fromIndex
是从某个索引值开始检测,如果为负值,则按升序从arr.length + fromIndex
的索引开始搜索。默认为 0。可以省略
2.2 指数操作符
在 ES7 中引入指数运算符「**
」,用来实现幂运算,功能与 Math.pow 结果相同
2**3 == Math.pow(2,3);
3. ECMASript 8(2017)
3.1 async和await
async
和await
可以让异步代码执行时和同步代码一样
(1)async
-
async
的返回值为promise
对象 -
promise
对象的结果由async
函数执行的返回值决定
(2)await
-
await
必须卸载await
函数中 -
await
右侧的表达式一般是promise
对象 -
await
返回的是promise
成功的值 - 如果
await
的promise
失败了,就会抛出异常,需要通过try...catch
来捕获处理
async function process(array) {
for await (let i of array) {
doSomething(i);
}
}
3.2 Object.values 和 Object.entries
-
Object.values()
方法返回一个给定对象的所有可枚举属性值的数组
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']
-
Object.entries()
方法返回一个给定对象自身可遍历属性[key,value]
的数组
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
3.3 Object.getOwnPropertyDescriptors
该方法返回指定对象所有自身属性的描述对象,如果没有任何自身属性,则返回空对象。
3.4 String padding
在ES8中String新增了两个实例函数String.prototype.padStart
和String.prototype.padEnd
,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。
(1)头部插入:String.prototype.padStart
用法:String.padStart(targetLength,[padString])
- targetLength:当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
- padString:(可选)填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断,此参数的缺省值为 " "。
console.log('2'.padStart(4,'12345')) //1232
(2)结尾插入:String.prototype.padEnd
用法:String.padEnd(targetLength,padString])
- targetLength:当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。
- padString:(可选) 填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断,此参数的缺省值为 " ";
console.log('2'.padEnd(4,'12345')) //2123
4. ECMASript 9(2018)
4.1 Rest/Spread 属性
在ES6中引入了Rest 参数与 spread 扩展运算符,但是他们只针对数组,在ES9中为对象也提供了相同的属性。
const obj = {
a: 1,
b: 2,
c: 3
};
const { a, ...x } = obj;
// 作为函数参数
function obj({ a, ...x }) {
console.log(a) // 1
console.log(x) // {b: 2, c: 3}
}
// 拷贝对象
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { ...obj1, z: 4 }; // { a: 1, b: 2, c: 3, z: 4 }
4.2 Promise.finally()
使用Promise调用,成功会触发.then()
,失败会触发.catch()
。在有些情况下,如果我们想要在无论Promise成功还是失败情况下运行相同的代码,例如清除,删除对话,关数据库连接等,就可以使用.finally()
来完成需要的逻辑。
function doSomething() {
doSomething1()
.then(doSomething2)
.then(doSomething3)
.catch(err => {
console.log(err);
})
.finally(() => {
// finish here!
});
}
4.3 正则表达式命名捕获组
ES9 允许命名捕获组使用符号 ?<name>
,这样获取捕获结果可读性更强
const reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/,
match = reDate.exec('2020-05-20'),
year = match.groups.year, // 2020
month = match.groups.month, // 05
day = match.groups.day; // 20
如果匹配失败,就会返回undefined
4.4 正则表达式反向断言
ES9 的正则表达式支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选。
- “反向断言”指的是 x只有在y后面才匹配,必须写成
/(?<=y)x/
。比如,只匹配美元符号之后的数字:
/(?<=\$)\d+/.exec('$100'); // ["100", index: 1, input: "$100", groups: undefined]
- “否定反向断言”指的是 x只有不在y后面才匹配,必须写成
/(?<!y)x/
。比如,只匹配不在美元符号后面的数字:
/(?<!\$)\d+/.exec('€100'); // ["100", index: 2, input: " €100", groups: undefined]
4.5 正则表达式的dotAll模式
正则表达式中点.
匹配除回车外的任何单字符,标记s改变这种行为,允许行终止符的出现,例如:
/hello.world/.test('hello\nworld'); // false
/hello.world/s.test('hello\nworld'); // true
5. ECMASript 10(2019)
5.1 flat()、flatMap()
(1)Array.prototype.flat()
该方法可以按照指定的深度递归遍历数组,并将所有的元素与遍历到的子数组中的元素合并为一个新的数组。
- flat()方法的一大作用就是将数组降维( 数组扁平化)
var arr1 = [1, 2, [3, 4, [5, 6]]];
arr1.flat(); // [1, 2, 3, 4, [5, 6]]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat(2); // [1, 2, 3, 4, 5, 6]
递归的深度默认为1,可以使用Infinity
来递归任意的深度。
- 除了可以用来扁平化数组之外,还可以用来清空数组的空项:
var arr = [1, 2, 3, , 5];
arr.flat(); // [1, 2, 3, 5]
(2)Array.prototype.flatMap()
flatMap()
方法首先使用映射函数映射每个元素,然后将结果放在一个数组中。和map()
方法类似。
var arr = [1, 2, 3, 4];
arr.map(x => [x * 2]); // [[2], [4], [6], [8]]
arr.flatMap(x => [x * 2]); // [2, 4, 6, 8]
flatMap()
方法对原数组的每个成员执行一个函数,相当于执行Array.prototype.map()
,然后对返回值组成的数组执行flat()
方法。该方法返回一个新数组,不改变原数组。但是flatMap()
方法只能展开一层数组。
var arr = [1, 2, [3, 4, [5, 6]]];
var res = arr.flatMap(x => [x * 2])
console.log(res) // [2, 4, NaN]
5.2 trimStart()、trimEnd()
这两个方法用来去除字符串首尾的空白字符。
在ES5中有类似的方法:trim()
,该方法是去除字符串的首尾的空白字符。
5.3 Object.fromEntries()
在ES2018中新增了Object.entries()
方法,该方法是返回一个对象自身可枚举属性的键值对数组,其排列与使用for...in
循环遍历该对象时返回的顺序一致。
而 Object.fromEntries()
相当于Object.entries()
方法的反转。
该方法传入一个键值对的列表,并返回一个带有这些键值对的新对象。
- 将map转化为对象
const map = new Map([ ['foo', 'bar'], ['baz', 42] ]);
const obj = Object.fromEntries(map);
console.log(obj); // { foo: "bar", baz: 42 }
- 将数组转化为对象
const arr = [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ];
const obj = Object.fromEntries(arr);
console.log(obj); // { 0: "a", 1: "b", 2: "c" }
5.4 Function.prototype.toString()
toString() 方法返回一个表示当前函数源代码的字符串,包括空格是注释
5.5 基本数据类型BigInt
现在的基本数据类型有七种n,分别是: String、Number、Boolean、Null、Undefined、Symbol、BigInt