ES6新特性
很好的文档:
ES6 入门教程 - ECMAScript 6入门 (ruanyifeng.com)
1 let关键字
let 关键字用来声明变量,使用 let 声明的变量有几个特点:
不允许重复声明
块儿级作用域
不存在变量提升
不影响作用域链
1 | //声明变量 |
案例:点击 div 换色
1 |
|
2 const关键字
const 关键字用来声明常量,const 声明有以下特点
声明必须赋初始值
标识符一般为大写
不允许重复声明
值不允许修改
块儿级作用域
应用场景:声明对象类型使用 const,非对象类型声明选择 let
1 | //声明常量 |
暂时性死区
1
2
3
4 if (true) {
console.log(foo) // ReferenceError: Cannot accesee 'foo' before initialization
let foo = "bar"
}
优先推荐使用const,保证数据安全,确定一个变量之后需要重新赋值时,这时再用let
3 变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
1 | //数组的解构赋值 |
4 模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:
1 字符串中可以出现换行符
2 可以使用 ${xxx}(JS中的插值语法) 来嵌入动态的内容
1 | // 定义字符串 |
5 简化对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
1 | let name = '尚硅谷'; |
6 箭头函数
ES6 允许使用「箭头」(=>)定义函数。
1 | /** |
箭头函数的注意点:
1、如果形参只有一个,则小括号可以省略
2、函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
3、箭头函数 this 指向声明时所在作用域下 this 的值
4、箭头函数不能作为构造函数实例化
5、不能使用 arguments
1 | /** |
7 rest参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
1 | /** |
8 spread扩展运算符
扩展运算符(spread)也是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
1 | /** |
9 Symbol
9.1 Symbol基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol即使多次创建值,它们也是不同的:Symbol函数执行后每次创建出来的值都是独一无二的
Symbol 特点:
1、Symbol 的值是唯一的,用来解决命名冲突的问题
2、Symbol 值不能与其他数据进行运算
3、Symbol 定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys 来获取对象的所有键名
1 | //创建 Symbol |
ES2019(ES10):可以在创建Symbol值的时候传入一个描述description
9.2 Symbol内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
1、Symbol.hasInstance
当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法
2、Symbol.isConcatSpreadable
对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat()时,是否可以展开。
3、Symbol.species
创建衍生对象时,会使用该属性
4、Symbol.match
当执行 str.match(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值。
5、Symbol.replace
当该对象被 str.replace(myObject)方法调用时,会返回该方法的返回值。
6、Symbol.search
当该对象被 str.search (myObject)方法调用时,会返回该方法的返回值。
7、Symbol.split
当该对象被 str.split(myObject)方法调用时,会返回该方法的返回值。
8、Symbol.iterator
对象进行 for…of 循环时,会调用 Symbol.iterator 方法,返回该对象的默认遍历器
9、Symbol.toPrimitive
该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
10、Symbol. toStringTag
在该对象上面调用 toString 方法时,返回该方法的返回值
11、Symbol. unscopables
该对象指定了使用 with 关键字时,哪些属性会被 with环境排除。
9.3 Symbol作为属性名
我们通常会使用Symbol在对象中表示唯一的属性名
1 | const s1 = Symbol("abc") |
9.4 相同值的Symbol
1 | // 使用Symbol.for创建相同的Symbol |
10 迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
1、ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
2、原生具备 iterator 接口的数据(可用 for of 遍历)
a) Array
b) Arguments
c) Set
d) Map
e) String
f) TypedArray
g) NodeList
3、工作原理
a) 创建一个指针对象,指向当前数据结构的起始位置
b) 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
c) 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
d) 每调用 next 方法返回一个包含 value 和 done 属性的对象
**注: 需要自定义遍历数据的时候,要想到迭代器。**11 生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
1 | function * gen(){ |
代码说明:
1、* 的位置没有限制
2、生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到yield 语句后的值
3、yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next方法,执行一段代码
4、next 方法可以传递实参,作为 yield 语句的返回值
12 Promise
12.1 什么是promise
在通过new创建Promise对象时,我们需要传入一个回调函数,我们称之为executor,这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject
当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数;当我们调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数
1 | const promise = new Promise((resolve, reject) => { |
上面Promise使用过程,我们可以将它划分成三个状态:
待定(pending): 初始状态,既没有被兑现,也没有被拒绝。当执行executor中的代码时,处于该状态;
已兑现(fulfilled): 意味着操作成功完成。执行了resolve时,处于该状态;
已拒绝(rejected): 意味着操作失败。执行了reject时,处于该状态;
12.2 Executor
Executor是创建Promise时需要传入的一个回调函数,这个回调函数会被立刻执行,并且传入两个参数
1 | new Promise((resolve, reject) => { |
通常我们会在Executor中确定我们的Promise状态:
通过resolve,可以兑现(fulfilled)Promise的状态,我们也可以称之为已决议(resolved);
通过reject,可以拒绝(reject)Promise的状态;
注意:一旦状态被确定下来,Promise的状态会被锁死,该Promise的状态是不可更改的
在我们调用resolve的时候,如果resolve传入的值本身不是一个Promise,那么会将该Promise的状态变成兑现(fulfilled);在之后我们去调用reject时,已经不会有任何的响应了(并不是这行代码不会执行,而是无法改变Promise状态);
12.3 resolve不同值的区别
- 如果resolve传入一个普通的值或者对象,那么这个值会作为then回调的参数
- 如果resolve传入的是另外一个Promise,那么这个Promise会决定原Promise的状态
- 如果resolve传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,并且根据then方法的结构来决定Promise的状态
1 | new Promise((resolve, reject) => { |
1 | new Promise((resolve, reject) => { |
1 | new Promise((resolve, reject) => { |
12.4 then
then方法是Promise对象上的一个方法,它其实是放在Promise的原型上的Promise.prototype.then
接收两个参数
fulfilled的回调函数:当状态变成fulfilled时会回调的函数
reject的回调函数:当状态变成reject时会回调的函数
1 | promise.then(res => { |
多次调用
一个Promise的then方法是可以被多次调用的
- 每次调用我们都可以传入对应的fulfilled回调
- 当Promise的状态变成fulfilled的时候,这些回调函数都会被执行
1 | promise.then(res => { |
返回值
then方法本身的返回值是一个Promise
Promise处于的状态
- 当then方法中的回调函数本身在执行的时候,那么它处于pending状态
- 当then方法中的回调函数返回一个结果(普通的值,Promise,thenable值)时,那么它处于fulfilled状态,并且会将结果作为resolve的参数
- 当then方法抛出一个异常时,那么它处于reject状态
12.5 catch
catch方法也是Promise对象上的一个方法,它也是放在Promise的原型上的Promise.prototype.catch
多次调用
- 每次调用我们都可以传入对应的reject回调
- 当Promise的状态变成reject的时候,这些回调函数都会被执行
1 | promise.catch(err => { |
返回值
catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法
1 | // 抛出异常,执行catch |
12.6 finally
ES9新增的特性:表示无论Promise对象无论变成fulfilled还reject状态,最终都会被执行的代码。finally不接收参数
也为Promise的实例方法,存放在Promise的prototype上
1 | const promise = new Promise((resolve, reject) => { |
12.7 resolve
将现成的内容转为Promise使用,相当于new Promise,并且执行resolve操作
1 | Promise.resolve("why") |
- 参数是一个普通的值或者对象
- 参数本身是Promise
- 参数是一个thenable
12.8 reject
语法类似于resolve,只会将Promise对象的状态设置为reject状态,用法相当于new Promise,只是会调用reject
1 | Promise.reject("why") |
Promise.reject传入的参数无论是什么形态,都会直接作为reject状态的参数传递到catch
12.9 all
将多个Promise包裹在一起形参一个新的Promise
新的Promise状态由包裹的所有Promise共同决定
- 当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值 组成一个数组
- 当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数
1 | const p1 = new Promise((resolve, reject) => { |
12.10 allSettled
all方法有一个缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。 那么对于resolved的,以及依然处于pending状态的Promise,我们是获取不到对应的结果的
在ES11(ES2020)中,添加了新的API Promise.allSettled:
- 该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态;并且这个Promise的结果一定是fulfilled的
1 | Promise.allSettled([p1, p2, p3]).then(res => { |
allSettled的结果是一个数组,数组中存放着每一个Promise的结果,并且是对应一个对象的,这个对象中包含status状态,以及对应的value值
12.11 race
表示多个Promise相互竞争,谁先有结果,就使用谁的结果
1 | Promise.race([p1, p2, p3]).then(res => { |
12.12 any
any方法是ES12中新增的方法,和race方法类似
any方法会等到一个fulfilled状态,才会决定新Promise的状态;如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态。如果所有的Promise都是reject,那么会报一个AggregateError的错误
1 | Promise.any([p1, p2, p3]).then(res => { |
13 Set
13.1 Set的基本使用
类似于数组,但和数组的区别是元素不能重复,创建Set我们需要用Set构造函数
Set实现了iterator接口,所以可以使用扩展运算符...以及for...of遍历
应用:数组去重
1 | const set1 = new Set() |
13.2 Set的常见方法
1、set常见的属性
size:返回集合的元素个数
2、Set常用的方法
add(value) :增加一个新元素,返回当前集合
delete(value): 删除元素,返回 boolean 值
has(value):检测集合中是否包含某个元素,返回 boolean 值
clear():清空集合,没有返回值(返回 undefined)
forEach(callback, [,thisArg]):通过forEach遍历set
1 | //创建一个空集合 |
13.3 WeakSet使用
和Set类似的另外一个数据结构称之为WeakSet,也是内部元素不能重复的数据结构
和Set的区别:
1、WeakSet中只能存放对象类型,不能存放基本数据类型
2、WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收
WeakSet常见的方法
add(value):添加某个元素,返回WeakSet对象本身
delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型
has(value):判断WeakSet中是否存在某个元素,返回boolean类型
13.4 WeakSet的应用
WeakSet不能遍历
因为WeakSet只是对对象的弱引用,如果我们遍历获取到其中的元素,那么有可能造成对象不能正常的销毁,所以存储到WeakSet中的对象是没办法获取的
1 | const pwset = new WeakSet() |
14 Map
14.1 Map的基本使用
Map用于存储映射关系。之前只能通过对象存储映射关系,但是其中的key只能是字符串(ES6新增了Symbol);某些情况下我们可能希望通过其他类型作为key,比如对象,这个时候会自动将对象转成字符串来作为key
Map 也实现了iterator 接口,所以可以使用扩展运算符...以及for…of…进行遍历
1 | const obj1 = { name: "why" } |
1 | const obj1 = { name: "why" } |
14.2 Map的常用方法
1、Map常见的属性
size:返回 Map 的元素个数
2、Map常见的方法
set(key, value):增加一个新元素,返回当前 Map
get(key): 返回键名对象的键值
has():检测 Map 中是否包含某个元素,返回 boolean 值
clear():清空集合,返回 undefined
forEach(callback, [,thisArg]):通过forEach遍历Map
1 | //创建一个空 map |
14.3 WeakMap的使用
和Map类型的另外一个数据结构称之为WeakMap,也是以键值对的形式存在的。
和Map的区别
1、WeakMap的key只能使用对象,不接受其他的类型作为key
2、WeakMap的key对对象想的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象
WeakMap常见的方法
set(key, value):在Map中添加key、value,并且返回整个Map地域性
get(key):根据key获取Map中的value
has(key):判断是否包括某一个键值对,返回Boolean类型
delete(key):根据key删除一个键值对,返回Boolean类型
14.4 WeakMap的应用
WeakMap也是不能遍历的
因为没有forEach方法,也不支持通过
for...of的遍历
1 | // WeakMap((key(对象): value)):key是一个对象,弱引用 |
15 class类
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
知识点:
1 class 声明类
2 constructor 定义构造函数初始化
3 extends 继承父类
4 super 调用父级构造方法
5 static 定义静态方法和属性
6 父类方法可以重写
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
1 | //父类 |
16 数值拓展
16.1 二进制和八进制
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
ES2021新特性:数字过长,可以使用_作为连接符
1 const num5 = 100_000_000
16.2 Number.isFinite() 与 Number.isNaN()
Number.isFinite() 用来检查一个数值是否为有限的
Number.isNaN() 用来检查一个值是否为 NaN
16.3 Number.parseInt() 与 Number.parseFloat()
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
16.4 Math.trunc
用于去除一个数的小数部分,返回整数部分。
16.5 Number.isInteger
Number.isInteger() 用来判断一个数值是否为整数
17 对象拓展
ES6 新增了一些 Object 对象的方法
1 Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
2 Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象
3 __proto__、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型
18 模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
18.1 模块化的好处
模块化的优势有以下几点:
1 防止命名冲突
2 代码复用
3 高维护性
18.2 模块化规范产品
ES6 之前的模块化规范有:
1 CommonJS => NodeJS、Browserify
2 AMD => requireJS
3 CMD => seaJS
18.3 ES6模块化语法
模块功能主要由两个命令构成:export 和 import。
export 命令用于规定模块的对外接口
import 命令用于输入其他模块提供的功能
19 函数的参数
19.1 默认参数
ES6之前,函数参数是没用默认值的。ES6中,允许给函数一个默认值
1 | function foo(x = 20, y = 30) { |
1 | function foo() { |
默认值也可以和解构一起来使用
1 | // 写法一 |
参数的默认值通常会放到最后;默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了
19.2 剩余参数
ES6中引用了rest parameter,可以将不定数量的参数放入到一个数组中,如果最后一个参数是 … 为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组
剩余参数必须放到最后一个位置,否则会报错
1 | function foo(m, n, ...args) { |
剩余参数和arguments的区别
剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参;
arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作;
arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,而rest参数是ES6中提供 并且希望以此来替代arguments的;
19.3 展开语法
展开语法(Spread syntax): 可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开
展开语法的场景: 在函数调用时使用;在数组构造时使用;在构建对象字面量时,也可以使用展开运算符,这个是在ES2018(ES9)中添加的新特性;
注意:展开运算符其实是一种浅拷贝
- 本文标题:ES6新特性
- 本文作者:馨er
- 创建时间:2021-11-27 16:52:17
- 本文链接:https://sjxbbd.vercel.app/2021/11/27/f3d456410f00/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!