Symbol
概述
ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是ES6引入Symbol的原因。
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
Symbol值通过Symbol
函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
Symbol的特性就是唯一性
Symbol(符号)是一种新的基本类型值
基本使用
Symbol的使用就是直接圆括号调用,不能通过new来构造
基本使用
Symbol内部可以传入参数,参数的作用是对这个符合的描述
let a = Symbol('hello') console.log(a);
Symbol的唯一性
Symbol是代表唯一的意思,同值的Symbol是不相等的
let a = Symbol() let b = Symbol() console.log(a == b);
即使内部传入参数相同也不相等
let a = Symbol('hello') let b = Symbol('hello') console.log(a == b);
Symbol的内部参数
(1)Symbol内部如果是字符串,表示当前这个符合的描述信息
let a = Symbol('hello') console.log(a)
(2)Symbol内部如果是对象,并且有toString方法,返回的就是这个符合的描述
let a = Symbol({ a: 100, toString: function() { return "symbol的描述信息" } }) console.log(a);
(3)Symbol内部如果是数组,内部的参数会被扁平化,用逗号隔开
let a = Symbol([ 1, 2, 'a', 'b' ]) console.log(a);
Symbol的应用场景
Symbol可以来创建对象的内部属性,内部属性的特点是防止外部获取或者随意篡改
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 1 } obj.c = 2; console.log(obj);
symbol定义的属性,外部是无法获取的,因为我们知道symbol同值是不相等的。所以下面的途径是获取不到的
obj[Symbol("objKey")]
上面的结果会返回undefined,因为symbol("objKey") != symbol("objKey")
并且对象遍历symbol的时候是得不到这个key的
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 300 } for (let item in obj) { console.log(item); }
使用Object.keys方法也不能获取symbol对应的key
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 300 } console.log(Object.keys(obj));
获取对象中Symbol的key的方法
第一个方法是Object.getOwnPropertySymbols,返回的是只有symbol定义的key
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 10 } let result = Object.getOwnPropertySymbols(obj) console.log(result)
第二个方法是Reflect.ownKeys,返回的是所有的key,包含symbol定义的key
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 10 } let result = Reflect.ownKeys(obj) console.log(result)
这两种方法还是可以获取对象中symbol对应的值的
let sym = Symbol("objKey") let obj = { a: 1, b: 2, c: 3, [sym]: 10 } let result = obj[Object.getOwnPropertySymbols(obj)[0]] console.log(result)
共享符号
上面注册的都是普通符号,也可以注册共享符号
普通符号:
let a = Symbol()
共享符号:
let a = Symbol.for()
.for()就代表创建了一个共享的符号,内部参数也是描述信息
let str = Symbol.for("b"); let str2 = Symbol.for("b"); console.log(str == str2);
上面的结果返回的是true,机理是:Symbol.for()定义的符号代表共享符号,如果创建了共享符号,此时就相当于在全局创建了一个符号,此时如果再次创建相同描述的符号,就不会再创建新的了,而是将原来的抛出,所以结果是相等的。
Symbol.keyFor方法
来获取已经注册到全局的共享符号的描述信息
let str = Symbol.for("b"); console.log(Symbol.keyFor(str));
Symbol的注意事项
Symbol值不能与其他类型的值进行运算,会报错:
var str = Symbol('小明'); console.log("我是"+str)
Symbol值可以显式转为字符串:
var str = Symbol('小明'); let str2=String(str) let str3=str.toString() console.log(typeof str2) console.log(typeof str3)
Symbol值也可以转为布尔值,但是不能转为数值
var num = Symbol(2); let num2=Boolean(num); console.log(typeof num2)
此时改为数值就回报错
var num = Symbol(2); let num2=Number(num); console.log(typeof num2)