github编辑

一文总结 ES 新特性

一文总结 ES 新特性

总结并列出 ES 5 及之后的新特性

一、理解 ES

  1. 全称: ECMAScript (/ˈɛkməskrɪpt/)

    • 它是一种由 ECMA 组织(前身为欧洲计算机制造商协会)制定和发布的脚本语言规范

    • 我们学习的 JavaScript 就是 ECMA 的实现

  2. JS 包含三个部分:

    • ECMAScript(JS 基础、核心部分)

    • 扩展 → 浏览器端

      • BOM(浏览器对象模型)

      • DOM(文档对象模型)

    • 扩展 → 服务器端

      • Node.js

  3. ES 的几个重要版本

    • 之前的为 ES 3(ES 4 夭折了,没发布)

    • ES 5:2009 年发布

    • ES 6(ES 2015):2015 年发布,也称为 ECMA 2015——重点(之后的 ES 就以年份命名)

    • ES 7(ES 2016):2016 年发布,也称为 ECMA 2016

二、ES 5 新特性

ES 5 对 JS 进行了修修补补,大概可以分为以下几类:

1、严格模式

理解:

  • 运行模式分为正常(混杂)模式与严格模式

  • 严格模式使得 JavaScript 在更严格的语法条件下运行

目的/作用:

  • 使得 Javascript 在更严格的条件下运行

  • 消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为

  • 消除代码运行的一些不安全之处,保证代码运行的安全

使用:

  • 全局函数第一条语句定义为:"use strict"

  • 如果浏览器不支持,只解析为一条简单的语句,没有任何副作用

语法和行为改变:

  • 声明定义变量必须用 var(没有隐式的全局变量了,你要创建全局变量必须是显式的)

  • 禁止自定义的函数中的 this 关键字指向全局对象(windowglobal),不管是 fn() 在全局调用还是 apply()call() 默认都不会指向全局对象

  • 创建 eval 作用域,更安全

  • 不准使用 with

  • arguments 只保存原始参数,对形参的赋值不会对 arguments 有影响,不准用 arguments.callerarguments.callee

  • 不支持八进制字面量,比如 var a = 015 会报错

  • 对象字面量或函数形参中,如果有重复的键名就会报错

  • 如果一个属性的 writeablefalse,给这个属性赋值会报错

  • 如果一个属性的 configurablefalse,则 delete 这个属性会报错

2、JSON 序列化和反序列化

  • 作用: 用于在 JSON 字符串与 JS 对象/数组相互转换

  • JSON.stringify(obj/arr) JS 对象(数组)转换为 JSON 数据(字符串)

  • JSON.parse(json) JSON 字符串转换为 JS 对象(数组)

3、Object 扩展

ES 5 给 Object 扩展了一些静态方法

  • Object.keys(), Object.create(), Object.defineProperty, Object.defineProperties, Object.getOwnPropertyDescriptor(), Object.getOwnPropertyNames(obj),Object.getPrototypeOf(obj)

  • Object.seal(), Object.freeze(), Object.preventExtensions(), Object.isSealed(), Object.isFrozen(), Object.isExtensible()

常用的两个:

create

Object.create(prototype[, descriptors]):创建一个新的对象,返回值是新对象

  • 作用:使用现有的对象来作为新创建对象的原型

  • 为新的对象指定新的属性,并对属性进行描述

    • value:指定值

    • writable:标识当前属性值是否是可修改的,默认为false

    • configurable:标识当前属性是否可以被删除,默认为false

    • enumerable:标识当前属性是否能用for in枚举,默认为false

defineProperties

Object.defineProperties(object, descriptors):为指定对象定义扩展多个属性

  • get 方法:用来得到当前属性值的回调函数

  • set 方法:用来监视当前属性值变化的回调函数

惰性求值:点击才给值(什么时候要什么时候给),会再次调用 get 方法

惰性求值
  • 什么时候调用:

    • get 方法:获取扩展属性值的时候 get 方法自动调用

    • set 方法:监听

  • 存储器属性:setter、getter 一个用来存值,一个用来取值

对象本身也有两个方法:

  • get propertyName(){}

  • set propertyName(){}

4、Array 扩展

Array.isArray(arr):判断一个对象 arr 是否是数组

Array.prototype.indexOf(value):得到值在数组中的第一个下标

Array.prototype.lastIndexOf(value):得到值在数组中的最后一个下标

Array.prototype.forEach(function(item, index, array){}[, asThis]):遍历数组,返回值是 undefined

Array.prototype.map(function(item, index, array){}[, asThis]):遍历数组返回一个新的数组(每一项是回调函数的返回值)

Array.prototype.filter(function(item, index, array){}[, asThis]):遍历过滤出一个子数组,返回一个由条件为 true 的元素组成的新数组

Array.prototype.reduce(function(accumulator, item, index, array)[, initValue])Array.prototype.reducearrow-up-right 对数组中的每个元素按序执行一个提供的回调函数,每次执行回调函数会将之前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值

Array.prototype.reduceRight:从右到左

Array.prototype.some(function(){item, index, array}[, asThis]):数组中是否至少有一个元素符合回调函数给定的条件,有则返回 true,没有返回 false

Array.prototype.every(function(item, index, array){}[, asThis]):判断一个数组内的所有元素是否都能通过指定函数的测试,返回布尔值(回调函数有三个参数,第一个为当前遍历的对象、第二个为当前的下标、第三个为数组本身,方法还接受第二个参数,将作为 this

5、Function 扩展

函数新增 bind 方法,Function.prototype.bind(asThis),将函数内的 this 绑定为 asThis,并将函数返回

强制绑定 this 使用 call/applybind

  • this 的值通过函数调用的时候确定

  • 五种函数调用形式

    • fnthis 是默认值,undefinedwindow

    • obj.x.fn()this 是前面调用的内容 obj.x,例如 btn.addEventListener 里面 this 就是 btn

    • call(asThis, args)apply(asThis, [args])this 就是传的 asThis

    • new fn(args)this 就是新创建的对象

🔖 面试题:区别 bind()call()apply()

fn.bind(asThis, args):指定函数中的 this,并返回函数(不会立即调用),一般用在回调函数绑定其他对象的 this

fn.call(asThis, args):指定函数中的 this,并调用函数

fn.apply(asThis, [args]):指定函数中的 this,并调用函数

总结:三个都可以给 fn 指定 thisbind 不会调用 fncallapply 都会调用 fncall 的其他参数依次以逗号分隔,apply 的其他参数以数组形式传递

6、Date扩展

  • Date.now():得到当前时间值,之前 new Date()

  • Date.prototype.toISOString:新增方法,会返回一个 ISO 格式的字符串( YYYY-MM-DDTHH:mm:ss.sssZ

  • new Date(string)Date.parse(string) 新增对 ISO 格式的支持

7、其他

  • 新增 String.prototype.trim,去除字串头尾空格

  • 尾逗号不报错,即多余的逗号不会报错,如 {a: 1, b: 2,}

  • 属性名可以使用关键字和保留字了,例如 {if: 1, else: 2}

  • NaNInfinityundefined 都是常量了,不可更改

  • parseInt() 第二个参数默认为 10

  • /regexp/ 正则字面量每次都会产生一个新的对象

三、ES 6 新特性

ES 6 新增了很多特性,让 JS 变得非常好用

1、2 个声明变量的新关键字

ES 6 中新增了块作用域,{} 包裹的地方就是一个块,ES 5 中没有块级作用域(只有全局和函数作用域)

let 关键字

作用:与 var 相似,用于声明一个变量

特点:

  • 在块作用域内有效

  • 不能重复声明

  • 不会预处理,不存在变量提升

应用:

循环遍历加监听

使用 let 代替 var 是趋势

const 关键字

作用:定义一个常量

特点

  • 不能修改

  • 其他特点同 let

应用

保存不用改变的数据

let 和 const 声明的变量都是有块级作用域的

let 和 const 声明变量在块作用域内都有暂时性死区,即在声明之前使用该变量会报错

2、变量(对象)的解构赋值

理解:

  1. 从对象或数组中提取数据,并赋值给多个变量

  2. 将包含多个数据的对象/数组一次赋值给多个变量

数据源:对象/数组

目标:{a, b}/[a, b]

对象的解构赋值:let {n, a} = {n:'tom', a:12} 把对象中的值赋值出来(根据属性名 key)

数组的解构赋值:let[a, b] = [1, 'luwang'] (根据下标)

用途:数组匹配、对象匹配、参数匹配(给多个形参赋值)

3、各种数据类型的扩展

(1) 字符串

模板字符串

  • 作用:简化字符串的拼接

  • 模板字符串必须用两个 "`" 包裹起来,ESC 下面那个键

  • 变量的部分使用 ${xxx} 定义

字符串支持 Unicode

  • String.fromCodePoint

  • String.prototype.codePointAt

新增一些方法

  • String.prototype.includes(str):判断是否包含指定的字符串

  • String.prototype.startsWith(str):判断是否以指定字符串开头

  • String.prototype.endsWith(str):判断是否以指定字符串结尾

  • String.prototype.repeat(count):重复指定次数

(2) 数值

二进制与八进制表示法:二进制用 0b,八进制用 0o

新增方法:

  • Number.EPSILON:最小精度

  • Number.isFinite(i):判断是否是有限大的数字

  • Number.isNaN(i):判断是否是NaN

  • Number.isInteger(i):判断是否是整数

  • Number.isSafeInteger(i)

  • Number.parseInt(str):将字符串转换为对应的数值

  • Math.acoshMath.hypotMath.imulMath.sign

  • Math.trunc(i):直接去除小数部分

(3) 对象

简化的对象写法(短语法)

  • 省略同名的属性值

  • 省略方法的 function

属性名支持表达式,需要用方括号括起来:

属性简写和解构赋值结合使用:

  • 在函数的参数中使用对象的解构赋值,可以避免在函数体内部再次对参数对象进行解构赋值(const {id, name} = user

  • 函数的参数如果是一个对象的成员,可以使用对象简写方式({id: id, name: name}

  • {data: res} 等同于 {data: data}data 是一个变量,res 是一个新的变量,可以用于解构赋值(获取到等号右边的 data.data

复制对象

Object.assign(target, source1, source2..):将源对象的属性复制到目标对象上

判断是否相等

Object.is(v1, v2):判断2个数据是否完全相等

__proto__ 属性

__proto__ 属性:隐式原型属性。ES 6 中能直接操作__proto__属性,但是不推荐使用

(4) 数组

  • Array.from(v):将伪数组对象或可遍历对象转换为真数组

  • Array.of(v1, v2, v3):将一系列值转换成数组

  • find(function(value, index, arr){return true}):找出第一个满足条件返回true的元素

  • findIndex(function(value, index, arr){return true}):找出第一个满足条件返回 true 的元素下标

  • fill:填充数组

  • copyWithin:复制数组中一系列元素到同一数组指定的起始位置

  • entries:返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键/值对

  • keys:返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键

  • values:返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的值

(5) 函数

Ⅰ、箭头函数

让函数写法更简便

基本语法:

  • 没有参数:const fn = () => console.log('xxxx') 箭头前的()不能省略

  • 一个参数:i => i+2 可以省略

  • 大于一个参数:(i,j) => i+j ()不能省略

  • 函数体不用大括号:默认返回结果

  • 函数体如果有多个语句,需要用 {} 包围

使用场景:多用来定义回调函数

特点:

  • 简洁

  • 箭头函数没有自己的 this,箭头函数的 this 不是调用的时候决定的,而是在定义的时候所处的对象就是它的 this

  • 扩展理解:箭头函数的 this 看外层是否有函数

    • 箭头外层有函数,this 是外层函数的 this

    • 箭头外层无函数,thiswindow

Ⅱ、参数处理

3 点运算符/点点点运算符

第一种用法:在函数中,rest(可变)参数

  • 通过形参左侧的 ... 来表达,取代 arguments 的使用

  • arguments 灵活,只能是最后部分形参参数

    • arguments 是伪数组,有 length,但是没有数组的一般方法,不能使用 forEach 遍历

    • calleearguments 的一个属性,等于函数本身,递归的时候可以写为:arguments.callee()

参数

第二种用法——扩展/展开运算符,可以分解出数组或对象中的数据

Ⅲ、形参的默认值

  • 定义形参时指定其默认的值

  • 当不传入参数的时候默认使用形参里的默认值

(6) 正则表达式

  • 正则表达式字面量添加 Unicode 支持(u 标记)

  • 正则表达式添加 y 标记,支持粘滞匹配

4、新增数据类型

(1) Symbol 类型

前言:ES 5 中对象的属性名都是字符串,容易造成重名,污染环境

概念:ES 6 中添加了一种原始数据类型 symbol(已有的数据类型:String、Number、boolean、null、undefined、对象)

特点:

  • Symbol 属性对应的值是唯一的,解决命名冲突问题

  • Symbol 值不能其他数据进行计算,包括与字符串拼串

  • for in、for of 遍历时不会遍历 symbol 属性

使用:

  • 调用 Symbol 函数得到 symbol 值

  • 传参标识

  • 内置 Symbol 值

    • 除了定义自己使用的 Symbol 值以外,ES 6 还提供了 11 个内置的 Symbol 值(查看官方文档)

    • 对象的 Symbol.iterator 属性,指向该对象的默认遍历器方法

(2) Set/Map 容器结构

容器: 能保存多个数据的对象,同时必须具备操作内部数据的方法

任意对象都可以作为容器使用,但有的对象不太适合作为容器使用(如函数)

Set 的特点:保存多个 value,value 是不重复 ====>数组元素去重

Map 的特点:保存多个 key-value,key 是不重复,value 是可以重复的

API:

  • Set 容器:无序不可重复的多个 value 的集合体

    • Set():创建一个空的 Set 容器

    • Set(arr):创建一个 Set 容器,同时将 arr 数组(其中 arr 是一维数组)中的元素添加到 Set 容器中(去重)

    • add(value):向 Set 容器中添加一个 value

    • delete(value):删除 Set 容器中指定的 value

    • clear():清空 Set 容器中的所有元素

    • has(value):判断 Set 容器中是否存在指定的 value

    • size:获取 Set 容器中元素的个数

  • Map 容器:无序的 key、不重复的多个 key-value 的集合体

    • Map():创建一个空的 Map 容器

    • Map(arr):创建一个 Map 容器,同时将 arr 数组(其中 arr 是二维数组)中的元素添加到 Map 容器中(去重)

    • set(key, value):向 Map 容器中添加一对 key-value

    • get(key):获取 Map 容器中指定 key 对应的 value

    • delete(key):删除 Map 容器中指定的 key-value

    • clear():清空 Map 容器中的所有元素

    • has(key):判断 Map 容器中是否存在指定的 key

    • size:获取 Map 容器中元素的个数

(3)WeakSet 和 WeakMap 类型

  • WeakSet 对象是一些对象值的集合。且其与 Setarrow-up-right 类似,WeakSet 中的每个对象值都只能出现一次。在 WeakSet 的集合中,所有对象都是唯一的。

    • WeakSet 只能是对象的集合,而不能像 Setarrow-up-right 那样,可以是任何类型的任意值。

    • WeakSet弱引用:集合中对象的引用为引用。如果没有其他的对 WeakSet 中对象的引用,那么这些对象会被当成垃圾回收掉。

  • WeakMap 的 key 只能是 Object 类型。 原始数据类型arrow-up-right 是不能作为 key 的(比如 Symbolarrow-up-right)。

    • 原生的 WeakMap 持有的是每个键对象的“弱引用”,WeakMap 的 key 是不可枚举的

(4)TypedArray 类型

5、class 类

ES6 中新增的语法,用于实现面向对象编程

通过 class 关键字定义类,实现类的继承

(1) 之前实现继承

回顾:原型、构造函数、构造函数+原型——继承

继承

(2) class 定义类

在类中通过 constructor() 定义构造方法(相当于构造函数)

  • 类声明和类表达式的区别

    • 类声明:类声明不可以省略类名,类名是标识符

    • 类表达式:类表达式的类名是可选的,如果有类名,类名是标识符

  • constructor() 构造方法

    • 通过 new 关键字调用类时,会自动调用 constructor() 构造方法

    • constructor() 构造方法是类中的默认方法,如果类中没有显式定义构造方法,那么类中会有一个隐式的、默认的空的 constructor() 构造方法

    • 通过 constructor() 构造方法可以给实例对象添加属性

继承

(3) class 类的继承

  • 一般方法:xxx () {}

  • 用 extends 来定义子类(实现类的继承)

  • 用 super() 来调用父类的构造方法

  • 子类方法自定义:将从父类中继承来的方法重新实现一遍(重写从父类继承的一般方法)

  • 在一个构造方法中可以使用 super 关键字来调用父类的构造方法

  • 在派生类中(子类),super() 必须要先调用,然后才能使用 this 关键字,否则会报错

  • super 关键字也可以用来调用父类的普通方法

  • extends 关键字用来实现类的继承,extends 后面跟父类的名称(也可以是内建对象)

(4) class 类的静态方法

  • 通过 static 关键字来定义静态方法

  • 静态方法是通过类来调用的,不能通过实例对象来调用

  • 静态方法中的 this 指向类本身

(5) class 类的 getter 和 setter 方法

  • 通过 get 和 set 关键字来定义 getter 和 setter 方法

  • getter 和 setter 方法是通过实例对象来调用

  • getter 和 setter 方法中的 this 指向实例对象

(6) class 类的静态属性

  • 通过 static 关键字来定义静态属性

  • 静态属性是通过类来调用的,不能通过实例对象来调用

  • 静态属性中的 this 指向类本身

(7) 私有类字段(属性和方法)

  • 私有类字段是指类中只能在类的内部访问的字段(属性和方法)

  • 私有类字段可以通过在字段名前面添加 # 来定义

6、Promise 对象

理解:

  • Promise 对象代表了某个将要发生的事件(通常是一个异步操作)

  • ES 6 的 Promise 是一个构造函数,用来生成 promise 实例

  • 解决回调地狱(回调函数的层层嵌套,编码是不断向右扩展,阅读性很差);有了 promise 对象,可以将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(回调地狱)

  • 能以同步编码的方式实现异步调用

  • 在 ES 6 之前原生的 JS 中是没这种实现的,一些第三方框架(jQuery)实现了 Promise

  • promise 对象的 3 个状态:

    • pending:待定状态

    • fullfilled:成功状态

    • rejected:失败状态

  • 在同一个 Promise 中只能 pending 到 pending、pending 到 fullfilled、pending 到 rejected,不能成功之后又失败或失败之后在成功

  • 应用:

    • 使用 promise 实现超时处理

    • 使用 promise 封装处理 Ajax 请求

(1) Promise 的基本使用

ES 6 中定义实现 API(使用 Promise 基本步骤):

例子:

例如:新闻、新闻的评论,只发新闻的内容;在接着根据新闻的 id 拿取这个新闻下的评论

  • new Promise() 创建一个新的 Promise 对象

    • 参数:回调函数(函数中有两个参数,resolve、reject)

    • resolve() 将 Promise 对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去

    • reject() 将 Promise 对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去

  • 创建的 Promise 对象可以调用一些方法

    • then():添加状态改变时的回调函数

    • catch():添加状态改变时的回调函数

    • finally():添加状态改变时的回调函数

    • all():将多个 Promise 实例,包装成一个新的 Promise 实例

    • race():将多个 Promise 实例,包装成一个新的 Promise 实例

    • resolve():将现有对象转为 Promise 对象

    • reject():返回一个新的 Promise 实例,该实例的状态为 rejected

(2) Promise 的链式调用

生成的 Promise 对象可以进行链式调用,即 then() 方法返回的是一个新的 Promise 对象,可以继续调用 then() 方法

7、Iterator 迭代器

概念:iterator 是一种接口机制,为各种不同的数据结构提供统一的访问机制

作用:

  • 为各种数据结构,提供一个统一的、简便的访问接口

  • 使得数据机构的成员能够按照某种次序排列

  • ES 6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费

工作原理

  • 创建一个指针对象(遍历器对象),指向数据结构的起始位置

  • 第一次调用 next 方法,指针自动指向数据结构的第一个成员

  • 接下来不断调用 next 方法,指针会一直往后移动,直到指向最后一个成员

  • 没调用 next 方法返回的是一个包含 value 和 done 的对象 {value: 当前成员的值, done: 布尔值}

    • value 表示当前成员的值,done 对应的布尔值表示当前的数据的结构是否遍历结束

    • 当遍历结束的时候返回的 value 值是 undefined,done 值为 false

原生具备 Iterator 接口的数据,可用 for...of 遍历

扩展理解

  • 当数据结构上部署了 Symbol.iterator 接口,该数据就是可以用 for of 遍历

  • 当使用 for of 去遍历目标数据的时候,该数据会自动去找 Symbol.iterator 属性(Symbol.iterator 属性指向对象的默认遍历器方法)

    • Array

    • arguments

    • set 容器

    • map 容器

    • String

    • ……

for-of 循环:可以遍历任何容器(Set、Map)、数组、对象、伪/类对象、字符串、可迭代的对象

例如

8、Generator 生成器

概念:

  • ES 6 提供的解决异步编程的方案之一

  • Generator 函数是一个状态机,内部封装了不同状态的数据

  • 用来生成遍历器对象

  • 可暂停函数(惰性求值),yield 可暂停,next 方法可启动。每次返回的是 yield 后的表达式结果

特点:

  • function 与函数名之间有一个星号

  • 内部用 yield 表达式来定义不同的状态

    例如:

generator 函数返回的是指针对象,而不会执行函数内部逻辑

调用 next 方法函数,内部逻辑开始执行,遇到 yield 表达式停止,返回 {value: yield后的表达式结果/return后的返回结果(如果没写,返回undefined),done: boolean值(后面还有返回false,没有返回true)}

再次调用 next 方法会从上一次停止时的 yield 处开始,直到最后

yield 语句返回结果通常为 undefined,当调用 next 方法时传参内容会作为启动时 yield 语句的返回值

补充:

  • 对象的 Symbol.iterator 属性,指向遍历器对象

例如:

  • 发送 ajax 请求获取新闻内容

  • 新闻内容获取成功后再次发送请求,获取对应的新闻评论内容

  • 新闻内容获取失败则不需要再次发送请求

9、模块

导入

  • 静态的 import 语句用于导入由另一个模块导出的绑定

  • 在浏览器中,import 语句只能在声明了 type="module"script 的标签中使用

  • 还有一个类似函数的动态 import(),它不需要依赖 type="module" 的 script 标签

语法:

导出

在创建 JavaScript 模块时,export 语句用于从模块中导出实时绑定的函数、对象或原始值,以便其他程序可以通过 importarrow-up-right 语句使用它们

10、其他

五、ES 2016

新增了两个新特性

1、指数操作

指数运算符(幂): **

2、数组新方法

Array.prototype.includes(value): 判断数组中是否包含指定 value

六、ES 2017

1、async/await 函数

概念:真正意义上去解决异步回调的问题,同步流程表达异步操作

本质:Generator 的语法

语法:

特点:

  • 不需要像 Generator 去调用 next 方法,遇到 await 等待,当前的异步操作完成就往下执行

  • 返回的总是 Promise 对象,可以用 then 方法进行下一步操作

  • async 取代 Generator 函数的 *,await 取代 Generator 的 yield

  • 语义上更为明确,使用简单,暂时没有任何副作用

获取新闻内容案例

改进一下,由于这种写法 error 并不会显示错误信息

给个模板

2、对象

  • Object.values:返回对象的所有值

  • Object.entries:返回对象的所有键值对

3、字符串填充

padStart()padEnd() 分别可以在字符串位数不足的时候向头部和尾部进行填充内容

第一个参数是总位数,第二个参数为位数不足时填充的内容

例如:

4、参数可以有多余的逗号

5、其他

  • getOwnPropertyDescriptors:获取对象的所有属性,包括不可枚举的属性

  • 共享内存和原子操作

后续好用的新特性

问号

可选链?.

双问号??

两个结合使用

由于现在开发都会用到 Babel 转译代码,所以可以放心使用这些新特性

最后更新于