symbol是什么?
-
symbol是一种原始类型。
-
Symbol()函数会返回symbol类型的值,具有唯一性。
-
symbol的值可以作为对象的key值。
-
原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持,即不在支持 new Symbol()语句,可以通过Symbol([description])来创建symbol值;(现有的包装器对象如new Boolean,new String,new Number因为历史遗留原因仍可被创建)。
var sym1 = Symbol(); var sym2 = Symbol(); sym1 == sym2 //false sym2.toString();//"Symbol()"
symbol不可枚举
Symbols 在 for…in 迭代中不可枚举。另外,Object.getOwnPropertyNames() 不会返回 symbol 对象的属性,但是你能使用 Object.getOwnPropertySymbols() 得到它们。
var obj = {};
obj[Symbol("a")] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";
for (var i in obj) {
console.log(i); // logs "c" and "d"
}
console.log(Object.getOwnPropertyNames(obj)) // ["c", "d"]
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(a), Symbol(b)]
Symbols 与 JSON.stringify()
当使用 JSON.stringify() 时,以 symbol 值作为键的属性会被完全忽略:
JSON.stringify({[Symbol("foo")]: "foo"}); // '{}'
Symbol 包装器对象作为属性的键
当一个 Symbol 包装器对象作为一个属性的键时,这个对象将被强制转换为它包装过的 symbol 值:
var sym = Symbol("foo");
var obj = {[sym]: 1};
obj[sym]; // 1
obj[Object(sym)]; // still 1
Symbol的应用(私有化属性)
现在有了一个模块
function getModule() {
return {
_data: 'world',
hello(){
console.log(this._data);
}
}
}
const mod = getModule();
mod.hello(); // => world
但是使用的人很容易篡改
const mod = getModule();
mod._data = 'bug'
mod.hello(); // => bug
当别人使用你的模块的时候并不想让他们碰_data,因为你认为这个是私有的。
解决办法一:万能的闭包。
function getModule(module) {
let _data = 'world';
return (function(){
return {
hello(){
console.log(_data)
}
}
})()
}
const mod = getModule();
mod._data = 'bug'
mod.hello(); // => world
解决了私有的问题,但是出现了另一个问题。
调试的时候,根本无法从模块的外面知道这个模块到底有什么私有的数据。
解决方案二:引入Symbol
const data = Symbol('data');
function getModule() {
return {
[data]: 'world',
hello(){
console.log(this[data])
}
}
}
这样,你在返回的对象上不管怎么赋值,都不会出现覆盖。可以被其他人随便封装。
const m = getModule();
m.data = 'bug';
m.hello(); // => world
m[Symbol('data')] = 'bug';
m.hello(); // => world
而且还可以使用nodejs的 util.inspect(object,[showHidden],[depth],[colors])看内部的数据。
utils.inspect(m,{showHidden:true})