js--Symbol 符号基本数据类型
前言
ECMAScript 6 中新增了 Symbol 符号这一基本数据类型,那么Symbol 是用来干什么的,对开发又有什么帮助呢?本文来总结记录一下 Symbol 的相关知识点。
正文
Symbol (符号)是 ECMAScript 6 新增的一种基本数据类型。符号是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一的标识符,不会发生属性冲突的危险,符号就是用来创建唯一记号,进而用作非字符串形式的对象属性。
1、符号的创建
var firstSymbol = Symbol() console.log(firstSymbol); //Symbol()
上面的代码直接调用Symbol()方法创建了一个符号类型的变量,也可以在Symbol方法中传入一个参数对符号变量进行描述,将来可以通过这个字符串来调试代码。但是,这个字符串参数与符号定义或标识完全无关。如下:
var secondSymbol = Symbol("foo") console.log(secondSymbol); //Symbol("foo") var thirdSymbol = Symbol("foo") console.log(secondSymbol == thirdSymbol); //false
Symbol 符号类型不像其他数据类型一样可以通过 new 来创建原始值的包装对象。若强行使用 new 会报语法错误。如果你确实想使用符号包装对象,可以借用 Object() 函数。如下:
var myStr = new String("name") console.log(typeof myStr);//object // var mySymbol = new Symbol()//Symbol is not a constructor at new Symbol (<anonymous>) var mySym = Symbol() var myWrapSym = Object(mySym) console.log(typeof myWrapSym);//object
2、从全局的 Symbol 注册表设置和取得 Symbol
如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册表中创建并重用符号。
(1)Symbol.for()
Symbol.for() 对每个字符串键都执行幂等操作。第一次使用某个字符串调用时,它会检查全局运行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。后续使用相同字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
var fooGlobalSymbol = Symbol.for('foo'); // 创建新符号 var otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号 console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true // 即使采用相同的符号描述,在全局注册表中定义的符号跟使用 Symbol() 定义的符号也并不等同: var localSymbol = Symbol('foo'); var globalSymbol = Symbol.for('foo'); console.log(localSymbol === globalSymbol); // false //此外,注册表中使用的键同时也会被用作符号描述。 console.log(localSymbol);//Symbol(foo) var emptyGlobalSymbol = Symbol.for(); console.log(emptyGlobalSymbol); // Symbol(undefined)
(2)Symbol.keyFor()
Symbol.keyFor() 来查询全局注册表,这个方法接收符号,返回该全局符号对应的字符串键。如果查询的不是全局符号,则返回 undefined 。
var s = Symbol.for('foo'); console.log(Symbol.keyFor(s)); // foo // 创建普通符号 var ss = Symbol('bar'); console.log(Symbol.keyFor(ss)); // undefined //如果传给 Symbol.keyFor() 的不是符号,则该方法抛出 TypeError : // Symbol.keyFor(123); // TypeError: 123 is not a symbol
3、使用符号作为属性
凡是可以使用字符串或数值作为属性的地方,都可以使用符号。这就包括了对象字面量属性和Object.defineProperty() / Object.defineProperties() 定义的属性。对象字面量只能在计算属性语法中使用符号作为属性。后两者可以用于添加属性语法。
var s1 = Symbol("s1"); var s2 = Symbol("s2"); var s3 = Symbol("s3"); var s4 = Symbol("s4"); var obj = { [s1]: "s1 val" } console.log(obj);//{Symbol(s1): "s1 val"} Object.defineProperty(obj, s2, { value: "s2 val" }); console.log(obj);//{Symbol(s1): 's1 val', Symbol(s2): 's2 val'} Object.defineProperties(obj, { [s3]: { value: "s3 val" }, [s4]: { value: "s4 val" } }) console.log(obj);//{Symbol(s1): "s1 val",Symbol(s2): "s2 val",Symbol(s3): "s3 val",Symbol(s4):"s4 val"}
类似于 Object.getOwnPropertyNames() 返回对象实例的常规属性数组, Object.getOwnProperty-Symbols() 返回对象实例的符号属性数组。这两个方法的返回值彼此互斥。 Object.getOwnProperty-Descriptors() 会返回同时包含常规和符号属性描述符的对象。
var ss1 = Symbol('foo') var info = { name: 123, age: 1232 } console.log(Object.getOwnPropertyNames(info));//['name', 'age'] Object.defineProperty(info, ss1, { value: "ss1 val" }) console.log(Object.getOwnPropertySymbols(info));//[Symbol(foo)] console.log(typeof Object.getOwnPropertySymbols(info)[0]);//'symbol' console.log(Object.getOwnPropertyDescriptors(info));//{name: {…}, age: {…}, Symbol(foo): {…}} console.log(Reflect.ownKeys(info));// ['name', 'age', Symbol(foo)] console.log(info[ss1]);//'ss1 val'
Symbol 作为属性名,该属性不会出现在 for...in、for...of 循环中,也不会被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify() 返回。
var person = { name: "personName", age: 18 } var sym = Symbol("sex") Object.defineProperty(person, sym, { value: "sexValue" }) for (const key in person) { console.log(key); }// name age console.log(Object.keys(person));//["name","age"]
写在最后
以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长踩坑之路会持续更新一些工作中常见的问题和技术点。最后,祝各位coder,节日快乐。