在明白Symbol值使用目的后,就来学习如何创建Symbol值。
有三种获取symbol的方法:
- 调用Symbol()函数创建Symbol值
- 调用Symbol.for()方法来创建Symbol值
- 使用标准定义的symbol,例如:Symbol.iterator。标准根据一些特殊用途定义了少许的几个symbol。
1.使用Symbol函数来创建值
var a = Symbol();
var b = Symbol("test");
var c = Symbol("test");
console.log(typeof a); // symbol
console.log(a); // Symbol()
console.log(b); // Symbol(test)
console.log(a===b); // false
console.log(b===c); // false
Symbol函数创建了独一无二的值,在什么时候都不会相等。
console.log(a)打印出了Symbol(),这是代表Symbol值,具体是什么不用关心,只用知道它是Symbol值且不会和其它值相等即可。
传入的参数只是为了在控制台区分不同的Symbol值,没有其它作用。
注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。也就是说,由于Symbol值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
2.调用Symbol.for()方法来创建Symbol值
在使用Symbol()函数创建Symbol值时,创建的都是独一无二的值,我们通过一个变量来引用这个值。那我们能不能直接获取Symbol值呢?
var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
var s3 = Symbol('foo');
s1 === s2 // true
s1 === s3 // false
上面的代码解释:
第一行代码:Symbol.for(‘foo’)方法首先会在全局的symbol注册表中查询有没有key为’foo’的Symbol值,有则返回这个Symbol值,否则会在全局的symbol注册表中注册一个key为’foo’的Symbol值。
第二行代码:Symbol.for(‘foo’)方法重复上面的步骤,不过第一行代码已经在全局注册表中注册了一个key为’foo’的Symbol值,这时候直接引用那个值即可,所以s1和s2全等。
第三行代码:Symbol()函数创建了一个Symbol值,foo是它在控制台的描述符,Symbol函数不会在symbol注册表中注册任何值,这样就保证了Symbol()函数创建的值不会引用其他值,是独一无二的。
Symbol.for(key)
key既是创建的Symbol值在控制台的描述符,也是在全局注册表中的识别符。Symbol.for(key)创建的Symbol值是全局共享的。
function f(){
var x = Symbol.for('foo');
return x;
}
var y = Symbol.for('foo');
console.log(y===f()); //true
虽然在函数中创建了一个Symbol值,但是这个值注册在了全局注册表中,所以在函数外可以查询到那个值。有一个问题,函数没执行也能创建吗?
Symbol.keyFor(sym)
我们知道了Symbol.for(key)可以在全局注册表中注册一个键为key的Symbol值,Symbol.keyFor(sym)方法则用来获取 symbol 注册表中与某个 symbol 关联的键
var s1 = Symbol.for('foo');
var key = Symbol.keyFor(s1);
console.log(key); // foo
3.内置的Symbol值
ES6添加了一些新方法,为了保证这些方法名不与用户定义的方法名冲突,使用内置的Symbol值来作为属性名或方法名。
如对象的Symbol.iterator属性,指向该对象的默认遍历器方法
内置的Symbol值保存在Symbol对象(构造函数)的属性中,通过访问这些属性就能获取这些特殊的Symbol值。
可以看看有哪些内置的Symbol值
现在我们来为对象添加一个新属性
var obj = {
x:1
};
var sym = Symbol("x");
obj[sym] = 2;
console.log(obj);
obj对象中有了属性x,我们为obj对象添加一个新属性,这个属性名的值是Symbol值,这样就保证了新添加的属性不会和任何属性重名。