JavaScript中的Symbol数据类型

        Symbol(符号)是ES6新增的数据类型。符号是原始值,且符号实例是唯一的、不可变的。符号的用途是确保对象属性使用唯一的标识符,不会发生属性冲突的危险。

        1.符号的基本用法

        符号是需要使用Symbol()函数初始化。因为符号本身是原始类型,所以typeof操作符对符号返回symbol。

let sym = Symbol();
console.log(typeof sym); // symbol

        调用Symbol函数时,也可以传入一个字符串参数作为对Symbol的描述,将来可以通过这个字符串来调试代码。但是这个字符串参数与Symbol定义或者标识完全没有关系。

let firstSymbol = Symbol();
let secondSymbol = Symbol();

let fooFirstSymbol = Symbol('foo');
let fooSecondSymbol = Symbol('foo');

console.log(firstSymbol == secondSymbol); // false
console.log(fooFirstSymbol == fooSecondSymbol); // false

        最重要的是,Symbol()函数不能与new关键字一起作为构造函数使用。这样是为了避免创建符号包装对象,像使用Boolean、String或Number那样,它们都支持构造函数且可用于初始化包含原始值的包装对象。

let myBoolean = new Boolean();
console.log(typeof myBoolean); // object

let myString = new String();
console.log(typeof myString); // object

let myNumber = new Number();
console.log(typeof myNumber); // object

let mySymbol = new Symbol();
console.log(typeof myNumber); // TypeError: Symbol is not a constructor

         如果确实想使用符号包装对象,可以借用Object()函数:

let mySymbol = Symbol();
let myWrappedSymbol = Object(mySymbol);
console.log(typeof myWrappedSymbol); // object

         2.使用全局符号注册表

        如果运行时的不同部分需要共享和重用符号实例。那么可以用一个字符串作为键,在全局符号注册表中创建并重用符号。
        为此需要使用Symbol.for()方法:

let fooGlobalSymbol = Symbol.for('foo');
console.log(typeof fooGlobalSymbol); // symbol

        Symbol.for()对每个字符串键都执行幂等操作。第一次使用某个字符串调用时,他会检查全局运行时注册表,发现不存在对应的符号,于是就会生成一个新的符号实例并添加到注册表中。后续使用相同字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。

let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
let otherFooSymbol = Symbol.for('foo'); // 重用已有符号
console.log(fooGlobalSymbol === otherFooSymbol); // true

        即使采用相同的符号描述,在全局注册表中定义的符号跟使用Symbol()定义的符号也并不相同:

let localSymbol = Symbol('foo');
let globalSymbol = Symbol.for('foo');
console.log(localSymbol === globalSymbol); // false

        全局注册表中的符号必须使用字符串键来创建,因此作为参数穿个Symbol.for()的任何值都会被转换为字符串。此外,注册表中使用的键同时也会被用作符号描述。

let oneSymbol = Symbol.for();
let twoSymbol = Symbol.for('111');
console.log(oneSymbol, twoSymbol); // Symbol(undefined) Symbol(111)

        还可以使用Symbol.keyFor()来查询全局注册表,这个方法接收符号,返回该全局符号对用的字符串键。如果查询的不是全局符号,则返回undefined。如果传给Symbol.keyFor()的不是符号,则该方法抛出TypeError:

// 创建全局符号
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s));  // foo
// 创建普通符号
let s2 = Symbol('bar');
console.log(Symbol.keyFor(s2)); // undefined
Symbol.keyFor(111); // TypeError: 111 is not a symbol

        3.使用符号作为属性

        凡是可以使用字符串或数值作为属性的方法,都可以使用符号。这就包括了对象字面量属性和Object.defineProperty()/Object.defineProperties()定义的属性。对象字面量只能在计算属性语法中使用符号作为属性。

let s1 = Symbol('foo'),
        s2 = Symbol('bar'),
        s3 = Symbol('baz'),
        s4 = Symbol('qux');
    let o = {
        [s1]: 'foo val'
    }
    // 也可以这么写   o[s1] = 'foo val';

    console.log(o);  // {Symbol(foo): 'foo val'}
    Object.defineProperty(o, s2, {value: 'bar val'});
    console.log(o); // {Symbol(foo): 'foo val', Symbol(bar): 'bar val'}
    Object.defineProperties(o, {
        [s3]: {value: 'bar val'},
        [s4]: {value: 'qux val'}
    });
    console.log(o);
    // {Symbol(foo): 'foo val', Symbol(bar): 'bar val', Symbol(baz): 'bar val', Symbol(qux): 'qux val'}

        4.常用内置符号 

        ECMAScript6引入了一批常用内置符号,试试用于暴露语言内部行为,开发者可以直接访问、重写或模拟这些行为。这些内置符号都以Symbol工厂函数字符串属性的形式存在。
        这些内置符号最重要的用途之一就是重新定义他们,从而改变原生结构的行为。比如,我们知道for-of循环会在相关对象上使用Symbol.iterator属性,那么就可以通过在自定义对象上重新定义Symbol.iterator的值,来改变for-of在迭代该对象时的行为。
        这些内置符号也没有什么特别之处,他们就是全局函数Symbol的普通字符串属性,指向一个符号的实例。所有的内置符号属性都是不可写、不可枚举、不可配置的。
        注意:在提到ECMAScript规范时,经常会引用符号在规范中的名称,前缀为@@。比如,@@iterator指的就是Symbol.iterator。

        5.Symbol的其他知识点(本篇暂时不讲,只列出)

        Symbol.asyncIterator、Symbol.hasInstance、Symbol.isConcatSpreadable、Symbol.iterator、Symbol.match、Symbol.replace、Symbol.search、Symbol.species、Symbol.split、Symbol.toPrimitive、Symbol.toStringTag、Symbol.unscopables。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值