es6入门-Symbol、Iterator、for...of

Symbol

  是一种数据类型、不是对象。表示独一无二的值,其他6中数据类型:Undefined、Null、Boolean、String、Number、Object。

let p = Symbol();
typeof p    //"symbol"

  Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,用来区分相同名称的Symbol值。

let p = Symbol();
let o = Symbol();
p      //Symbol();
o      //Symbol();
let p = Symbol("p1");
p       //Symbol("p1");

1.Symbol值不能与其他类型的值进行运算,会报错
2.Symbol值可以显示转换为字符串。
  String(p); //Symbol(“p1”);
  p.toString(); //Symbol(“p1”);
3.Symbol值可以转为布尔值,不能转为数值。Boolean(p); //true

Symbol值作为对象的属性名
使用Symbol值定义属性时,必须放在括号中。由Symbol定义的属性是公开的,不是私有属性。

var p = Symbol();
//1.
var a = {};
a[p] = 'hello';
//2.
var a = {
    [p]:'hello'
}
//3.
Object.defineProperty(a,p,{value:'hello'});

对象的属性名不能使用点运算符‘.’,点运算符后总是字符串。
Symbol定义常量,不用担心后续会定义相同的值。

消除魔术字符串(某些与代码形成强耦合的字符串和数值),把这些魔术字符串写成变量。
Symbol的属性名遍历
  用Symbol值作为属性名不会被for…in、for…of、Object.keys()、Object.getOwnPropertyNames()返回。

1.Object.getOwnPropertySymbols()返回数组。
2.Reflect.ownKeys()返回所有类型的键名。

利用Symbol值的遍历特点,定义一些非私有的内部方法的效果。

 Symbol.for():接收一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。有则返回;无则创建,会登记在全局中作为搜索对象。
 Symbol.keyFor():以一个Symbol值变量为参数,返回一个已经存在的Symbol类型值的key。

//1.
var s = Symbol.for("p");
var p = Symbol.for("p");
s===p          //true
//2.返回已登记的Symbol值
var t = Symbol.keyFor(p);        //undefined
var p = Symbol.for("p");      
Symbol.keyFor(p);             //"p"

Symbol.for()登记的值是全局的,在不同的iframe或service worker中取得同一个值。

内置的Symbol值
1.Symbol.hasInstance属性指向一个内部方法,判断是否为某个构造函数的实例;对象使用instanceof运算符会调用这个方法。
2.Symbol.isConcatSpreadable属性等于布尔值,表示对象使用Array.prototype.concat()时时候是否可以展开;

//Symbol.isConcatSpreadable属性默认true,可以展开
let arr = ['a','b'];
['c','d'].concat(arr,'e');         //['c','d','a','b','e']
//类似数组的对象 Symbol.isConcatSpreadable属性默认false,需手动打开
let obj = {length:2,0:'a',1:'b'};
['c','d'].concat(obj,'e');          //['c','d',obj,'e']
obj[Symbol.isConcatSpreadable] = true;
['c','d'].concat(obj,'e');          //['c','d','a','b','e']

3.Symbol.iterator属性指向默认遍历器方法,for…of循环会调用这个方法。
4.Symbol.species属性指向一个方法,对象作为构造函数创造实例时会调用。
即this.constructor[Symbol.species]存在,就会使用这个属性作为构造函数来创造新实例对象。
5.Symbol.match指向一个函数,这个属性存在时,执行str.match(myObject)返回匹配的值。
6.Symbol.replace属性指向一个方法,replace();
7.Symbol.search属性指向一个方法,search();
8.Symbol.split属性指向一个方法,split();
9.Symbol.toPrimitive属性指向一个方法,对象被转为原始类型的值时会调用这个方法,返回该对象对应的原始类型值。
10.Symbol.toStringTag属性指向一个方法,执行toString方法返回的字符串中,表示对象的类型。
11.Symbol.unscopables属性指向一个对象,使用with关键字时哪些属性会被排除在外。

Iterator、for…of

next()、return()、throw()
  Iterator只是把接口规格加到数据结构上,遍历器和所遍历的数据结构实际上是分开的。
具有原生的Iterator接口:数组、类似数组的对象、Set、Map
1.Symbol.iterator属性上部署Iterator

class RangeIterator{
    constructor(start,stop){
        this.value = start;
        this.stop = stop;
    }
    [Symbol.iterator](){
        return this;
    }
    next(){
        var value = this.value;
        if(value<this.stop){
            this.value++;
            return {done:false,value:value};
        }else{
            return {done:true,value:undefined};
        }
    }
}
function range(start,stop){
    return new RangeIterator(start,stop);
}
for(var value of range(0,3)){
    console.log(value);
}

2.对象添加Iterator接口

let obj = {
    data:['hello','word'],
    [Symbol.iterator](){
        const self = this;
        let index = 0;
        return{
            next(){
                if(indexreturn{
                        value:self.data[index++],
                        done:false
                    };
                }else{
                    return {value:undefined,done:true};
                }
            }
        }
    }
}

3.类似数组的对象(存在数值键名和length属性),直接引用数组的Iterator接口。

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
//
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
//
let obj = {
    1:"hello",
    3:"world",
    length:2,
    [Symbol.iterator]:[][Symbol.iterator]
}
//1.以数值作为属性名时,按下标0开始,如果属性名超出length,遍历时取不到值length后的值。
for(let item of obj){
    console.log(item);      //undefined,"hello"
}

有了遍历器接口,数据结构可以使用for…of,也可以使用while循环。
解构赋值、扩展运算符、yield*会默认调用Symbol.iterator方法。
for…of /Array.from()/Map()/WeakMap()/Set()/WeakSet()/Promise.all()/Promise.race()
字符串是一个类似数组的对象。

遍历器对象的return(),throw()
return()方法:for…of循环提前退出(出错、break语句、continue语句),或者一个对象在遍历完成后需要清理或释放资源,可部署return()方法。
**return()方法必须返回一个对象
for…in循环,只能获得对象的键名,不能直接获取键值;可以直接循环遍历对象的键名。可以使用Object.keys()方法将对象的键名生成一个数组,然后遍历这个数组。

for(var key of Object.keys(someObject)){
    console.log(key+":"+someObject[key]);
}

for…in 也会遍历手动添加的其他键,包括原型链上的键。以任意顺序遍历键名。

你可能感兴趣的:(ES6特性)