ES6 ------ 基础(二)
Symbol
Symbol 原始数据类型, 表示独一无二的值 。
特点:
- Symbol 的值是唯一的,用来解决命名冲突的问题。
- Symbol 值不能与其他数据进行运算。
- Symbol定义的对象属性不能使用 for…in 循环遍历, 但是可以使用Reflect.ownKeys来获取对象的所有键名。
- 1.创建 Symbol
let s = Symbol() console.log(s, typeof s) //Symbol() 'symbol' let s2 = Symbol('ES6') let s3 = Symbol('ES6') console.log(s2 === s3); //false
注意:Symbol 函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的 Symbol 函数的返回值是不相等的。
- 2.Symbol.for 创建
let s = Symbol.for('ECMAScript6') console.log(s, typeof s) //Symbol(ECMAScript6) 'symbol' let s4 = Symbol.for('ES6') let s5 = Symbol.for('ES6') console.log(s4 === s5) //true
Symbol.for() 类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。
3.不能与其他数据进行运算且Symbol 不能转为数值)
let s = Symbol() let result = s + 100 let result2 = s + s //Uncaught TypeError: Cannot convert a Symbol value to a number
4.可以显式转为字符串
let sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)' sym.toString() // 'Symbol(My symbol)' //实例属性 description,直接返回 symbol 的描述 const s = Symbol('My symbol') s.description // "My symbol"
5.可以转为布尔值
let sym = Symbol(); Boolean(sym) // true
数据类型总结:USONB
u undefined
s string symbol
o object
n null number
b boolean
Symbol 创建对象属性
向对象中添加方法
let youxi = { name:'狼人杀', [Symbol('say')]:function(){ console.log("我可以发言"); }, [Symbol('zibao')]:function(){ console.log("我可以自爆"); } } console.log(youxi);
Symbol 内置属性
- 1.Symbol.hasInstance:当其他对象使用 instanceof 运算符,判断是否为该对象的实例时,会调用这个方法。
class Person{ static [Symbol.hasInstance](param){ console.log(param); //{} console.log('我被用来检测类型'); return true } } let o = {} console.log(o instanceof Person); //true (取决于return返回的值)
- 2.Symbol.isConcatSpreadable:对象的 Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于 Array.prototype.concat() 时,是否可以展开。
const arr = [1,2,3] const arr2 = [4,5,6] arr2[Symbol.isConcatSpreadable] = false console.log(arr.concat(arr2)) //(4) [1, 2, 3, Array(3)]
迭代器
迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
1.ES6 创造了一种新的遍历命令 for … of 循环,Iterator 接口主要供 for…of 消费
2.原生具备 Iterator 接口的数据(可用 for… of 遍历)
Array、Arguments、Set、Map、String、TypeArray、Nodelist
for…of 和 for…in 的区别:
a). for…of 循环保存的是键值
b). for…in 循环保存的是键名
// 声明一个数组 const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'] // 使用 for...of 遍历数组 for(let v of xiyou){ console.log(v); //唐僧 孙悟空 猪八戒 沙僧 } // 使用 for...in 遍历数组 for(let v in xiyou){ console.log(v); //0 1 2 3 }
3.工作原理:
a).创建一个指针对象,指向当前数据结构的起始位置。
b).第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员。
c).接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
d).每调用 next 方法返回一个包含 value 和 done属性的对象
注意:需要自定义遍历数据的时候,要想到迭代器。
// 声明一个数组 const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'] let iterator = xiyou[Symbol.iterator]() // 调用对象的next方法 console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next());
迭代器自定义遍历对象
Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。
通过 for…of 使用迭代器自定义遍历对象
const banji = { name:"终极一班", stus:[ 'xiaoming', 'xiaohua', 'xiaoyue', 'xiaoyan' ], [Symbol.iterator](){ // 索引变量 let index = 0 // let _this = this return { next: function(){ if(index < _this.stus.length){ const result = {value: _this.stus[index], done: false} // 下标自增 index++ // 返回结果 return result }else{ return {value: undefined, done: true} } } } } } for(let v of banji){ console.log(v); }
生成器函数
生成器其实就是一个特殊的函数。
针对于异步编程的解决方案。
- 1.function 后要加一个 *,输出时不是使用 console.log 而是 .next()
function * gen(){ console.log("Hello generator"); } let iterator = gen() iterator.next() //输出:Hello generator
- 2.函数代码的分隔符 yield
function * gen(){ console.log(111); yield '熊大'; console.log(222); yield '熊二'; console.log(333); yield '光头强'; console.log(444); } let iterator = gen() iterator.next() // 111 iterator.next() // 222 iterator.next() // 333 iterator.next() // 444 //第一次调用iterator.next()打印111,以此类推。
- 3.for…of 输出它们
function * gen(){ yield '熊大'; yield '熊二'; yield '光头强'; } let iterator = gen() for(let v of gen()){ console.log(v); //熊大 熊二 光头强 }
生成器函数参数
function * gen(arg){ console.log(arg); let one = yield 111 console.log(one); let two = yield 222 console.log(two); let three = yield 333 console.log(three); } // 执行获取迭代器对象 let iterator = gen('AAA') console.log(iterator.next()); console.log(iterator.next('BBB')); console.log(iterator.next('CCC')); console.log(iterator.next('DDD'));
生成器函数实例
要求:1s 后控制台输出 111,再 2s 后 输出222,再 3s后输出 333
- 1.方法一:使用 setTimeout 实现(回调地狱)
setTimeout(() => { console.log(111); setTimeout(()=>{ console.log(222); setTimeout(()=>{ onsole.log(333); },3000) },2000) },1000)
历时 6 秒可以全部输出,但是代码缩进不断向前,不利于阅读和调试(回调地狱)。
- 2.方法二:使用生成器函数
function one(){ setTimeout(()=>{ console.log(111) iterator.next() },1000) } function two(){ setTimeout(()=>{ console.log(222) iterator.next() },2000) } function three(){ setTimeout(()=>{ console.log(333) iterator.next() },3000) } function * gen(){ yield one() yield two() yield three() } // 调用生成器函数 let iterator = gen() iterator.next()
生成器函数实例 2
模拟获取 用户数据、订单数据、商品数据。间隔一秒输出(异步)
function getUsers(){ setTimeout(()=>{ let data = '用户数据' // 调用 next 方法, 并且将数据传入 iterator.next(data) },1000) } function getOrders(){ setTimeout(()=>{ let data = '订单数据' iterator.next(data) },1000) } function getGoods(){ setTimeout(()=>{ let data = '商品数据' iterator.next(data) },1000) } function * gen(){ let users = yield getUsers() console.log(users); let orders = yield getOrders() console.log(orders); let goods = yield getGoods() console.log(goods); } // 调用生成器函数 let iterator = gen() iterator.next()
不积跬步无以至千里 不积小流无以成江海