ES6 入门第四章
Symbol基本使用
ES6 引入了一种新的原始数据类型Symbol。表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点
1) Symbol 的值是唯一的,用来解决命名冲突的问题
2) Symbol值不能与其他数据进行运算
3) Symbol定义的对象属性不能使用 for…in 循环遍历,但是可以使用Reflect。ownKeys 来获取对象的所有键名
- 创建Symbol
//创建Symbol
let s = Symbol();
console.log(s, typeof s);
let s2 = Symbol('人性的弱点');
let s3 = Symbol('人性的弱点');
console.log(s2 === s3);
2. Symbol.for 创建
//Symbol.for 创建
let s4 = Symbol.for('狼道');
console.log(s4,typeof s4);
let s4 = Symbol.for('狼道');
let s5 = Symbol.for('狼道');
console.log(s4 === s5);
注意事项
不能与其他数据进行运算
//不能与其他数据进行运算
let s = Symbol();
let result = s + 100;
//let result = s > 100;
//let result = s +'100';
Symbol 创建对象属性
let youxi = {
name:"狼人杀",
[Symbol('say')]: function(){
console.log("我可以发言")
},
[Symbol('zibao')]: function(){
console.log("我可以自爆")
}
}
console.log(youxi);
Symbol 内置值
除了定义自己使用的 Symbol 值以外,ES6 还提供了11个内置的Symbol值,指向语言内部使用的方法。
Symbol.hasInstance | 当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法 |
---|---|
Symbol.isConcatSpreadable | 对象的Symbol.isConcatSpreadable 属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开 |
Symbol.unscopables | 该对象指定了使用with 关键字时,哪些属性会被 with环境排除 |
Symbol.match | 当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值 |
Symbol.replace | 当该对象被 str.replace(myObject) 时,如果该属性存在,会调用它,返回该方法的返回值 |
Symbol.search | 当该对象被 str.search(myObject)方法调用时,会返回该方法的返回值 |
Symbol.split | 当该对象 str.split(myObject)方法调用时,会返回该方法的返回值 |
Symbol.iterator | 对象进行for…of循环时,会调用Symbol.iterator 方法,返回该对象的默认遍历器 |
Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值 |
Symbol.toStringTag | 在该对象上面调用 toString 方法时,返回该方法的返回值 |
Symbol.species | 创建衍生对象时,会使用该属性 |
- Symbol.hasInstance
class Person{
static [Symbol.hasInstance](param){
console.log(param);
console.log("我被用来检测类型了")
}
}
let o = {};
console.log(o instanceof Person);
class Person{
static [Symbol.hasInstance](param){
console.log(param);
console.log("我被用来检测类型了")
return true;
}
}
let o = {};
console.log(o instanceof Person);
Symbol.hasInstance 可以自己控制类型检测
- Symbol.isConcatSpreadable
const arr = [1,2,3];
const arr2 = [4,5,6];
console.log(arr.concat(arr2));
const arr = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));
迭代器 Iterator
迭代器(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
for…of 中的 of 前面的变量保存的是键值
//声明一个数组
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//使用 for...of 遍历数组
for(let v of xiyou){
console.log(v);
}
for…in 中的 in 前面的变量保存的是键名
//声明一个数组
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//使用 for...in 遍历数组
for(let v in xiyou){
console.log(v);
}
3)工作原理
a)创建一个指针对象,指向当前数据结构的起始位置
b)第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
c)接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
注:需要自定义遍历数据的时候,要得到迭代器。
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
let iterator = xiyou[Symbol.iterator]();
console.log(iterator);
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next());
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());
迭代器自定义遍历对象
//声明一个对象
const banji = {
name:"终极一班",
stus:[
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
[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);
}
生成器
生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完成不同。
function * gen(){
yield '一只没有耳朵';
yield '一只没有尾巴';
}
//生成器其实就是一个特殊的函数
//异步编程 纯回调函数 node fs ajax mongodb
function * gen(){
console.log("hello generator");
}
let iterator = gen();
console.log(iterator);
如果想gen()里面的内容运行,则需要next():
function * gen(){
console.log("hello generator");
}
let iterator = gen();
iterator.next();
yield 函数代码的分隔符
//函数代码的分隔符
function * gen(){
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一只没有尾巴';
console.log(333);
yield '真奇怪';
console.log(444);
}
let iterator = gen();
iterator.next();
iterator.next();
iterator.next();
iterator.next();
由上面的代码,得知:yield将gen()里面分成了四段,由next来控制输出几段
我使用了四次next,则四段都输出了。
遍历
//遍历
function * gen(){
yield '一只没有耳朵';
yield '一只没有尾巴';
yield '真奇怪';
}
let iterator = gen();
//遍历
for(let v of gen()){
console.log(v);
}
function * gen(){
yield '一只没有耳朵';
yield '一只没有尾巴';
yield '真奇怪';
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
done表示循环是否结束。
生成器函数参数
function * gen(arg){
console.log(arg);
yield 111;
yield 222;
yield 333;
}
//执行获取迭代器对象
let iterator = gen('AAA');
上面代码将不会输出gen()里面 的内容,需要加上next,才有输出。
function * gen(arg){
console.log(arg);
yield 111;
yield 222;
yield 333;
}
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(iterator.next());
生成器函数实例
实例1:
异步编程: 1s 后控制台输出 111 2s后输出 222 3s后输出 333
使用setTimeout实现
//回调地狱
setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
setTimeout(() => {
console.log(333);
}, 3000)
}, 2000)
}, 1000)
使用生成器函数实现
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 = '商品数据';
},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();