Symbol类型的使用
-
ES6 数据类型除了 Number 、 String 、 Boolean 、 Object、 null 和 undefined ,还新增了 Symbol
-
Symbol类型的特性:
- Symbol属性对应的值是唯一的,解决命名冲突问题
- Symbol的值不能与其他数据类型进行计算,字符串拼接也不行
- Symbol不能使用 for in 和 for of 遍历
-
基本使用:
let symbol = Symbol()
-
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
-
Symbol的内置值
- ES6中为Symbol提供了11个内置的值,指向语言内部使用的方法
- Symbol.iterator属性,通常用于定义对象的唯一属性
let obj = {
name:'jack',
age:18
}
obj[Symbol.iterator] = function(){
}
Iterator(遍历器)
-
概念:遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。
-
iterator主要作用
-
为各种数据结构,提供一个统一的、简便的访问接口
-
使得数据结构的成员能够按某种次序排列
-
ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费
-
-
Iterator 的遍历过程是这样的。
-
创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
-
第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
-
第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
-
不断调用指针对象的next方法,直到它指向数据结构的结束位置。
-
遍历结束时,value的值为undefined,done的值为true,是否执行的依据为done的值为false时。
- 每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
-
-
原生具备iterator接口数据(可使用for of 遍历)
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList (DOM)对象
-
for of方法的使用
-
for of 不能遍历普通对象
-
使用的iterator接口
-
剩余运算符使用的也是 iterator接口
for(let key of arr){ console.log(key) }
-
Symbol.iterator基本实现原理
function iterator(arr) {
// 相当于内置的指针对象
let index = 0
return {
next() {
// 判断使用三元运算符判断当前指针下标是否超过数组的长度
return index < arr.length ?
{ value: arr[index++], done: false } :
{ value: arr[index++], done: true };
}
}
}
let arr = [5, 4, 3, 2, 1]
//调用一次这个方法,就取出对应下标的值
let iter = iterator(arr)
console.log(iter.next())
Symbol.iterator底层实现原理
数组遍历实现
- 手动修改Array原型中的Symbol.iterator 指向到自定义函数中
Array.prototype[Symbol.iterator] = iteratorTool
- 修改原型对象方法后,自定义的iteratorTool()方法,不在接收参数,此时函数中的数组长度调用会发生错误。
- 在iteratorTool()方法中,this指向的是遍历的数组,是因为当调用for…of方法时,会触发arr数组中的Symbol.iterator属性中的方法。
- 首先将this保存,防止作用域污染
let _this = this
- 其次修改函数中的
arr.length
为_this.length
即可
- 首先将this保存,防止作用域污染
对象遍历和数组遍历共同实现
-
函数需要同时实现两种遍历形式,需要进行判断,当前this是数组还是对象,
- 使用 instanceof 关键字用于判断
_this instanceof Array
- 使用 instanceof 关键字用于判断
-
在对象中不存在下标概念,所以使用取下标的形式,不能将对象中的属性值拿出来
- 将需要遍历的对象转换成数组形式
Object.keys(obj)
- 数组形式下我们可以拿到所有属性的length长度
Object.keys(obj).length
,用于判断next()函数是否继续执行 - 将返回的对象中的value属性的值修改为对象取值形式
_this[Object.keys(obj)[index++]]
- 将需要遍历的对象转换成数组形式
Generator 函数(过渡异步处理-不常用)
-
Generator 函数的概念
- Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
- Generator 函数内部封装不同状态的数据
- 用来生成遍历器对象
- 可暂停函数(惰性求值),yield关键字进行暂停,next()方法启动。每次返回的是yield后的表达式执行的结果
-
Generator 函数的特性
- function与函数名之间有一个星号*
function* demo(){}
- 内部使用yield来定义不同状态,基本定义
- function与函数名之间有一个星号*
function* demo(){
let result = yield 1;
yield 2;
}
- 调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象
- 调用next()方法函数内部的逻辑开始执行[ 至少调用一次,函数体才会执行 ],遇到yield或return语句时停止。yield后面的那个表达式的值,作为返回的对象的value属性值
- 在次调用next()方法会从上一次的yield出开始执行,直到最后
- yield在未设定返回值是默认为undefined
3. Generator 函数的基本使用
- next()方法需要在得到调用函数的返回对象下使用
```
function* generatorTool(){
console.log('我要开始啦~')
yield 1
console.log('我在中间')
yield 2
console.log('我已经结束了~')
}
let Gt = generatorTool()
Gt.next()
```
- Generator 函数处理异步操作
-
在yield关键字后可以调用函数(进行数据请求等)
-
在调用的函数中使用next()方法,将对象指针下移,逻辑代码继续执行。
-
调用next()方法时可以进行传参,参数作为yield关键字后的表达式返回值
function AsyncTool(){ setTimeout(()=>{ let data = '我是数据' Gt.next(data) },2000) } function* generatorTool(){ let res = yield AsyncTool() yield AsyncTool(res) }
-
####async 函数的使用
-
概念:真正意义上解决了异步回调的问题,同步流程表达异步操作
-
本质:Generator的语法糖
-
async 函数的基本语法:
async function demo(){ await 异步操作; await 异步操作; }
4.async 函数的特性:
- 不需要像Generator去调用next()方法,遇到await关键字时等待,当前的异步操作完成后继续往下执行
- 返回的是一个Promise对象,可以使用then()方法进行操作
- async关键字取代了Generator函数的*号,await取代了yield
- 相对其他异步操作解决方案更简洁
5.async搭配Promise进行异步操作
- await关键字会自动识别Promise对象的state状态值,用于判断是否继续执行
function promiseTool(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('我执行了')
resolve(res)
},2000)
})
}
async function asyncTool(){
console.log('我开始了~')
let res = await promiseTool()
console.log('我继续')
await promiseTool(res)
console.log('我完事了')
}
asyncTool()