ES6新特性
馨er BOSS

ES6新特性

很好的文档:

ES6 入门教程 - ECMAScript 6入门 (ruanyifeng.com)

1 let关键字

let 关键字用来声明变量,使用 let 声明的变量有几个特点:

  • 不允许重复声明

  • 块儿级作用域

  • 不存在变量提升

  • 不影响作用域链

**应用场景:以后声明变量使用let就对了**
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//声明变量
let a;
let b,c,d;
let e = 100;
let f = 521, g = 'iloveyou', h = [];

//1. 变量不能重复声明
// let star = '罗志祥';
// let star = '小猪';

//2. 块儿级作用域 全局, 函数, eval
// if else while for
// {
// let girl = '周扬青';
// }
// console.log(girl);

//3. 不存在变量提升
// console.log(song);
// let song = '恋爱达人';

//4. 不影响作用域链
{
let school = '尚硅谷';
function fn(){
console.log(school);
}
fn();
}

案例:点击 div 换色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>点击 DIV 换色</title>
<link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css"
rel="stylesheet">
<style>
.item {
width: 100px;
height: 50px;
border: solid 1px rgb(42, 156, 156);
float: left;
margin-right: 10px;
}
</style>
</head>

<body>
<div class="container">
<h2 class="page-header">点击切换颜色</h2>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<script>
//获取div元素对象
let items = document.getElementsByClassName('item');

//遍历并绑定事件
for(let i = 0;i<items.length;i++){
items[i].onclick = function(){
//修改当前元素的背景颜色
// this.style.background = 'pink';
items[i].style.background = 'pink';
}
}

</script>
</body>

</html>

2 const关键字

const 关键字用来声明常量,const 声明有以下特点

  • 声明必须赋初始值

  • 标识符一般为大写

  • 不允许重复声明

  • 值不允许修改

  • 块儿级作用域

**注意: 对象属性修改和数组元素变化不会触发const错误**

应用场景:声明对象类型使用 const,非对象类型声明选择 let

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//声明常量
const SCHOOL = '尚硅谷';

//1. 一定要赋初始值
// const A;
//2. 一般常量使用大写(潜规则)
// const a = 100;
//3. 常量的值不能修改
// SCHOOL = 'ATGUIGU';
//4. 块儿级作用域
// {
// const PLAYER = 'UZI';
// }
// console.log(PLAYER);
//5. 对于数组和对象的元素修改, 不算做对常量的修改, 不会报错
const TEAM = ['UZI','MXLG','Ming','Letme'];
// TEAM.push('Meiko');

暂时性死区

1
2
3
4
if (true) {
console.log(foo) // ReferenceError: Cannot accesee 'foo' before initialization
let foo = "bar"
}

优先推荐使用const,保证数据安全,确定一个变量之后需要重新赋值时,这时再用let

3 变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//数组的解构赋值
const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr;
//对象的解构赋值
const lin = {
name: '林志颖',
tags: ['车手', '歌手', '小旋风', '演员']
};
let {name, tags} = lin;
//复杂解构
let wangfei = {
name: '王菲',
age: 18,
songs: ['红豆', '流年', '暧昧', '传奇'],
history: [
{name: '窦唯'},
{name: '李亚鹏'},
{name: '谢霆锋'}
]
};
let {songs: [one, two, three], history: [first, second, third]} =
wangfei;
**注意:频繁使用对象方法、数组元素,就可以使用解构赋值形式**

4 模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识,特点:

1 字符串中可以出现换行符

2 可以使用 ${xxx}(JS中的插值语法) 来嵌入动态的内容

1
2
3
4
5
6
7
8
9
10
// 定义字符串
let str = `<ul>
<li>沈腾</li>
<li>玛丽</li>
<li>魏翔</li>
<li>艾伦</li>
</ul>`;
// 变量拼接
let star = '王宁';
let result = `${star}在前几年离开了开心麻花`;

5 简化对象写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let name = '尚硅谷';
let slogon = '永远追求行业更高标准';
let improve = function () {
console.log('可以提高你的技能');
}
//属性和方法简写
let atguigu = {
name,
slogon,
improve,
change() {
console.log('可以改变你')
}
};
**注意:对象简写形式简化了代码,所以以后用简写就对了**

6 箭头函数

ES6 允许使用「箭头」(=>)定义函数。

1
2
3
4
5
6
/**
* 1. 通用写法
*/
let fn = (arg1, arg2, arg3) => {
return arg1 + arg2 + arg3;
}

箭头函数的注意点:

1、如果形参只有一个,则小括号可以省略

2、函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果

3、箭头函数 this 指向声明时所在作用域下 this 的值

4、箭头函数不能作为构造函数实例化

5、不能使用 arguments

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 2. 省略小括号的情况
*/
let fn2 = num => {
return num * 10;
};
/**
* 3. 省略花括号的情况
*/
let fn3 = score => score * 20;
/**
* 4. this 指向声明时所在作用域中 this 的值
*/
let fn4 = () => {
console.log(this);
}

let school = {
name: '尚硅谷',
getName(){
let fn5 = () => {
console.log(this);
}
fn5();
}
};
**注意:箭头函数不会更改** **this** **指向,用来指定回调函数会非常合适**

7 rest参数

ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 作用与 arguments 类似
*/
function add(...args){
console.log(args);
}
add(1,2,3,4,5);
/**
* rest 参数必须是最后一个形参
*/
function minus(a,b,...args){
console.log(a,b,args);
}
minus(100,1,2,3,4,5,19);
**注意:rest参数非常适合不定个数参数函数的场景**

8 spread扩展运算符

扩展运算符(spread)也是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 展开数组
*/
let tfboys = ['德玛西亚之力','德玛西亚之翼','德玛西亚皇子'];
function fn(){
console.log(arguments);
}
fn(...tfboys)
/**
* 展开对象
*/
let skillOne = {
q: '致命打击',
};
let skillTwo = {
w: '勇气'
};
let skillThree = {
e: '审判'
};
let skillFour = {
r: '德玛西亚正义'
};
let gailun = {...skillOne, ...skillTwo,...skillThree,...skillFour};

9 Symbol

9.1 Symbol基本使用

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。

Symbol即使多次创建值,它们也是不同的:Symbol函数执行后每次创建出来的值都是独一无二的

Symbol 特点:

1、Symbol 的值是唯一的,用来解决命名冲突的问题

2、Symbol 值不能与其他数据进行运算

3、Symbol 定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys 来获取对象的所有键名

1
2
3
4
5
6
7
8
9
10
11
//创建 Symbol
let s1 = Symbol();
console.log(s1, typeof s1);
//添加标识的 Symbol
let s2 = Symbol('尚硅谷');
let s2_2 = Symbol('尚硅谷');
console.log(s2 === s2_2);
//使用 Symbol for 定义
let s3 = Symbol.for('尚硅谷');
let s3_2 = Symbol.for('尚硅谷');
console.log(s3 === s3_2);
**注: 遇到唯一性的场景时要想到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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const s1 = Symbol("abc")
const s2 = Symbol("cba")

const obj = {}

obj[s1] = "abc"
obj[s2] = "cba"

Object.defineProperty(obj, s1, {
enumerable: true,
configurable: true,
writable: true,
value: "abc"
})

const info = {
[s1]: "abc",
[s2]: "cba"
}

console.log(Object.getOwnPropertySymbols(info))

const symbolKeys = Object.getOwnPropertySymbols(info)
for (const key of symbolKeys) {
console.log(info[key])
}

9.4 相同值的Symbol

1
2
3
4
5
6
7
8
9
10
// 使用Symbol.for创建相同的Symbol
const s1 = Symbol.for("abc")
const s2 = Symbol.for("abc")

console.log(s1 === s2) // true
// Symbol.keyFor方法获取对应的key
const key = Symbol.keyFor(s1)
console.log(key) // abc
const s3 = Symbol.for(key)
console.log(s2 === s3) // true

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
2
3
4
5
6
7
8
function * gen(){
yield '一只没有耳朵';
yield '一只没有尾巴';
return '真奇怪'; }
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

代码说明:

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
2
3
4
5
6
7
8
9
10
11
12
const promise = new Promise((resolve, reject) => {
// 调用resolve,那么then传入的回调会被执行
resolve("哈哈哈")
// 调用resolve,那么catch传入的回调会被执行
reject("错误信息")
})

promise.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})

上面Promise使用过程,我们可以将它划分成三个状态:

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。当执行executor中的代码时,处于该状态;

  • 已兑现(fulfilled): 意味着操作成功完成。执行了resolve时,处于该状态;

  • 已拒绝(rejected): 意味着操作失败。执行了reject时,处于该状态;

12.2 Executor

Executor是创建Promise时需要传入的一个回调函数,这个回调函数会被立刻执行,并且传入两个参数

1
2
3
new Promise((resolve, reject) => {
console.log("executor代码")
})

通常我们会在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
2
3
4
5
new Promise((resolve, reject) => {
resolve("normal resolve")
}).then(res => {
console.log("res: ", res)
})
1
2
3
4
5
6
7
8
9
10
11
new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第二个Promise的resolve")
}, 3000)
}))
}).then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})
1
2
3
4
5
6
7
8
9
new Promise((resolve, reject) => {
resolve({
then: function (resolve, reject) {
resolve("thenable value")
}
})
}).then(res => {
console.log("res:", res)
})

12.4 then

then方法是Promise对象上的一个方法,它其实是放在Promise的原型上的Promise.prototype.then

接收两个参数

  • fulfilled的回调函数:当状态变成fulfilled时会回调的函数

  • reject的回调函数:当状态变成reject时会回调的函数

1
2
3
4
5
6
7
8
9
10
11
12
promise.then(res => {
console.log("res:", res)
}, err => {
console.log("err:", err)
})

// 等价于
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})

多次调用

一个Promise的then方法是可以被多次调用的

  • 每次调用我们都可以传入对应的fulfilled回调
  • 当Promise的状态变成fulfilled的时候,这些回调函数都会被执行
1
2
3
4
5
6
7
8
9
10
11
promise.then(res => {
console.log("res1:", res)
})

promise.then(res => {
console.log("res2:", res)
})

promise.then(res => {
console.log("res3:", 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
2
3
4
5
6
promise.catch(err => {
console.log("err:", err)
})
promise.catch(err => {
console.log("err:", err)
})

返回值

catch方法也是会返回一个Promise对象的,所以catch方法后面我们可以继续调用then方法或者catch方法

1
2
3
4
5
6
7
8
9
// 抛出异常,执行catch
promise.catch(err => {
console.log("err1:", err)
throw new Error("error message")
}).then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err2:", err)
})

12.6 finally

ES9新增的特性:表示无论Promise对象无论变成fulfilled还reject状态,最终都会被执行的代码。finally不接收参数

也为Promise的实例方法,存放在Promise的prototype上

1
2
3
4
5
6
7
8
9
10
11
12
const promise = new Promise((resolve, reject) => {
// resolve("fulfilled")
reject("reject")
})

promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
}).finally(() => {
console.log("finally action")
})

12.7 resolve

将现成的内容转为Promise使用,相当于new Promise,并且执行resolve操作

1
2
3
Promise.resolve("why")
// 等价于
new Promise(resolve => resolve("why"))
  • 参数是一个普通的值或者对象
  • 参数本身是Promise
  • 参数是一个thenable

12.8 reject

语法类似于resolve,只会将Promise对象的状态设置为reject状态,用法相当于new Promise,只是会调用reject

1
2
Promise.reject("why")
new Promise((resolve, reject) => reject("why"))

Promise.reject传入的参数无论是什么形态,都会直接作为reject状态的参数传递到catch

12.9 all

将多个Promise包裹在一起形参一个新的Promise

新的Promise状态由包裹的所有Promise共同决定

  • 当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值 组成一个数组
  • 当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const p1 = new Promise((resolve, reject) => {

})
const p2 = new Promise((resolve, reject) => {

})
const p3 = new Promise((resolve, reject) => {

})
Promise.all([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})

12.10 allSettled

all方法有一个缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。 那么对于resolved的,以及依然处于pending状态的Promise,我们是获取不到对应的结果的

在ES11(ES2020)中,添加了新的API Promise.allSettled:

  • 该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态;并且这个Promise的结果一定是fulfilled的
1
2
3
4
5
Promise.allSettled([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})

allSettled的结果是一个数组,数组中存放着每一个Promise的结果,并且是对应一个对象的,这个对象中包含status状态,以及对应的value值

12.11 race

表示多个Promise相互竞争,谁先有结果,就使用谁的结果

1
2
3
4
5
Promise.race([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})

12.12 any

any方法是ES12中新增的方法,和race方法类似

any方法会等到一个fulfilled状态,才会决定新Promise的状态;如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态。如果所有的Promise都是reject,那么会报一个AggregateError的错误

1
2
3
4
5
Promise.any([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log("err:", err)
})

13 Set

13.1 Set的基本使用

类似于数组,但和数组的区别是元素不能重复,创建Set我们需要用Set构造函数

Set实现了iterator接口,所以可以使用扩展运算符...以及for...of遍历

应用:数组去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const set1 = new Set()
set1.add(10)
set1.add(14)
set1.add(16)
console.log(set1) // Set(3) { 10, 14, 16 }

const set2 = new Set([11, 15, 18, 11])
console.log(set2) // Set(3) { 11, 15, 18 }

const arr = [10, 20, 10, 44, 78, 44]
const set = new Set(arr)
const newArray1 = [...set]
const newArray2 = Array.from(set)
console.log(newArray1, newArray2) // {10, 20, 44, 78} {10, 20, 44, 78}

13.2 Set的常见方法

1、set常见的属性

size:返回集合的元素个数

2、Set常用的方法

add(value) :增加一个新元素,返回当前集合

delete(value): 删除元素,返回 boolean 值

has(value):检测集合中是否包含某个元素,返回 boolean 值

clear():清空集合,没有返回值(返回 undefined)

forEach(callback, [,thisArg]):通过forEach遍历set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建一个空集合
let s = new Set();
//创建一个非空集合
let s1 = new Set([1,2,3,1,2,3]);
//集合属性与方法
//返回集合的元素个数
console.log(s1.size);
//添加新元素
console.log(s1.add(4));
//删除元素
console.log(s1.delete(1));
//检测是否存在某个值
console.log(s1.has(2));
//清空集合
console.log(s1.clear());

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
2
3
4
5
6
7
8
9
10
const pwset = new WeakSet()
class Person {
constructor() {
pwset.add(this)
}
running(){
if(!pwset.has(this)) throw new Error("不能通过其他对象调用running方法")
console.log("running", this)
}
}

14 Map

14.1 Map的基本使用

Map用于存储映射关系。之前只能通过对象存储映射关系,但是其中的key只能是字符串(ES6新增了Symbol);某些情况下我们可能希望通过其他类型作为key,比如对象,这个时候会自动将对象转成字符串来作为key

Map 也实现了iterator 接口,所以可以使用扩展运算符...以及for…of…进行遍历

1
2
3
4
5
6
7
8
const obj1 = { name: "why" }
const obj2 = { age: 18 }

const map = new Map()
map.set(obj1, "abc")
map.set(obj2, "cba")
console.log(map.get(obj1)) // abc
console.log(map.get(obj2)) // cba
1
2
3
4
5
6
7
8
9
10
11
const obj1 = { name: "why" }
const obj2 = { age: 18 }


const map = new Map([
[obj1, "abc"],
[obj2, "cba"],
[obj1, "nba"]
])
console.log(map.get(obj1)) // nba
console.log(map.get(obj2)) // cba

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//创建一个空 map
let m = new Map();
//创建一个非空 map
let m2 = new Map([
['name','尚硅谷'],
['slogon','不断提高行业标准']
]);
//属性和方法
//获取映射元素的个数
console.log(m2.size);
//添加映射值
console.log(m2.set('age', 6));
//获取映射值
console.log(m2.get('age'));
//检测是否有该映射
console.log(m2.has('age'));
//清除
console.log(m2.clear());

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// WeakMap((key(对象): value)):key是一个对象,弱引用
const targetMap = new WeakMap()
function getDep(target, key) {
// 1. 根据对象(target)取出对应的Map对象
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}

// 2. 取出具体的dep对象
let dep = depsMap.get(key)
if (!dep) {
dep = new Map()
depsMap.set(key, dep)
}
return dep;
}

15 class类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

知识点:

1 class 声明类

2 constructor 定义构造函数初始化

3 extends 继承父类

4 super 调用父级构造方法

5 static 定义静态方法和属性

6 父类方法可以重写

ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//父类
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, pixel) {
super(brand, color, price);
this.screen = screen;
this.pixel = pixel;
}
//子类方法
photo(){
console.log('我可以拍照!!');
}
playGame(){
console.log('我可以玩游戏!!');
}
//方法重写
call(){
console.log('我可以进行视频通话!!');
}
//静态方法
static run(){
console.log('我可以运行程序')
}
static connect(){
console.log('我可以建立连接')
} }
//实例化对象
const Nokia = new Phone('诺基亚', '灰色', 230);
const iPhone6s = new SmartPhone('苹果', '白色', 6088,
'4.7inch','500w');
//调用子类方法
iPhone6s.playGame();
//调用重写方法
iPhone6s.call();
//调用静态方法
SmartPhone.run();

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
2
3
4
5
function foo(x = 20, y = 30) {
console.log(x, y)
}
foo(50, 100) // 50 100
foo() // 20 30
1
2
3
4
5
function foo() {
var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 20;
var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 30;
console.log(x, y)
}

默认值也可以和解构一起来使用

1
2
3
4
5
6
7
8
9
// 写法一
function foo1({name, age} = {name: "why", age: 18}) {
console.log(name, age)
}

// 写法二
function foo2({name = "why", age = 18} = {}) {
console.log(name, age)
}

参数的默认值通常会放到最后;默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了

19.2 剩余参数

ES6中引用了rest parameter,可以将不定数量的参数放入到一个数组中,如果最后一个参数是 … 为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组

剩余参数必须放到最后一个位置,否则会报错

1
2
3
4
function foo(m, n, ...args) {
console.log(m, n)
console.log(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 许可协议。转载请注明出处!