超级厉害的JavaScript —— ECMAScript 6 标准(4) —— Symbol

什么是Symbol

ES5的对象属性名都是字符串,很容易造成属性名冲突,这就需要一种机制实现属性名的独一无二,这就是Symbol要解决的问题。
Symbol是ES6新增的原始数据类型,表示独一无二的值,需要通过Symbol函数生成。


Symbol基础使用

Symbol函数接受一个字符串参数,表示对Symbol的描述,意味着参数相同的Symbol是不同的值。
如果参数是一个对象,就会调用该对象的toString方法。

var s1 = Symbol('a');
var s2 = Symbol('a');
var s3 = Symbol('b');

console.log(s1 == s2);//false
console.log(s1.toString(),s2.toString(),s3.toString());//Symbol(a),Symbol(a),Symbol(b)


var obj = {
    toString:function(){
        return 'abc';
    }
}
console.log(Symbol(obj))//Symbol(abc);

运算

Symbol不能与其他类型的值进行运算,但是,Symbol可以显示转为字符串和布尔值,但是不能转为数值。

var symbol = Symbol('a');
"a" + symbol;       //TypeError:can't convert symbel to string;

symbol.toString();  //Symbol(a)

Boolean(symbol);    //true

Number(symbol);     //Error

作为属性名

构建唯一的属性名是Symbol的主要功能,这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被覆盖。

var symbol = Symbol();

var a = {};
a[symbol] = "Hellow";

var a = {
    [symbol] : "Hellow"
};

var a = {};
Object.defineProperty(a,symbol,{value : "Hellow"});

以上三种赋值语句都会得到相同的结果,定义和提取属性的时候要注意点运算符都会将其理解成字符串,所以要用[]引导。


遍历

Symbol作为属性名的属性是不会出现在普通的遍历中,需要使用Object.getOwnPropertySymbols方法返回所有属性名是symbol构成的symbol数组。

var obj = {};
var symbolA = Symbol('a');
var symbolB = Symbol('b');

obj[symbolA] = "Hellow";
obj[symbolB] = "World";

var symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols );      //[Symbol(a),Symbol(b)]

还有一个APIReflect.ownKeys可以返回所有类型的键名,包括常规键名和Symbol键名:

let obj = {
    [Symbol()] : 1,
    a : 2,
    b : 3
}
console.log(Reflect.ownKeys(obj));//[Symbol(),'a','b']

复用的Symbol

Symbol()方法每次调用都会创建一个新的Symbol值,如果需要使用同一个Symbol,可以使用Symbol.for()方法。这个方法接受一个字符串作为参数,然后搜索有没有以这个参数作为名称的Symbol值,有则返回,没有则在全局环境中登记该Symbol

Symbol.for("bar") === Symbol.for("bar");                    //true
Symbol.for("bar") === Symbol("bar");                        //false
Symbol("bar") === Symbol("bar");                            //false

iframe = document.createElement("iframe");
iframe.src = String(window.location);
document.body.appendChild(iframe);
iframe.contentWindow.Symbol.for("bar") === Symbol.for("bar");//true

Symbol.keyFor()能回一个已登记的Symbol类型值得key,而没有对应的key在登记列表中的symbol 类型会返回undefined:

var symbolByFor = Symbol.for("foo");
var symbol = Symbol("foo");
console.log(symbolByFor,symbol);//"foo",undefined

内置的Symbol方法

Symbol.hasInstance

当其他对象使用instanceof运算符的时候判断是否该对象的实例时,会调用这个方法;
比如:foo instanceof Foo在语言内部,实际是这样的Foo[Symbol.hasInstance](foo)

class MyClass{
    [Symbol.hasInstance](foo){
        console.log("Symbol.hasInstance");
        return foo instanceof Array;
    }
}

console.log([] instanceof new MyClass());
/*
console:
Symbol.hasInstance
true
*/
//

直接和原型进行判断:

class MyClass{
    static [Symbol.hasInstance](foo){
        console.log("Symbol.hasInstance");
        return foo instanceof Array;
    }
}

console.log([] instanceof MyClass);
/*
console:
Symbol.hasInstance
true
*/
//

Symbol.isConcatSpreadable

表示该对象使用Array.prototype.concat()时,是否可以展开:

let arr1 = ["c","d"];
console.log(["a","b"].concat(arr1,"e"));//["a","b","c","d","e"]
console.log(arr1[Symbol.isConcatSpreadable]);//undefined

let arr2 = ["c","d"];
arr1[Symbol.isConcatSpreadable]=false;
console.log(["a","b"].concat(arr1,"e"));//["a","b",["c","d"],"e"]

数组的默认行为是可以展开的,Symbol.isConcatSpreadable属性等于trueundefined都会开启展开;
类似数组的对象也可以展开,但它的Symbol.isConcatSpreadable属性默认为false,必须手动打开:

let obj= {length : 2, 0 : "c" , 1 : "d"};
console.log(["a","b"].concat(obj,"e"));//["a","b",obj,"e"]

obj[Symbol.isConcatSpreadable]=true;
console.log(["a","b"].concat(obj,"e"));//["a","b","c","d","e"]

Symbol.species

指向当前对象的构造函数,创造实例时,默认会调用这个方法,即使用这个属性返回的函数当作构造函数,来创造新对象。

Symbol.match、Symbol.replace、Symbol.search、Symbol.splite

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值