文章目录
一、概念
Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:“new Symbol()”。
每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的
const symbol1 = Symbol();
const symbol2 = Symbol(42);
const symbol3 = Symbol('foo');
console.log(typeof symbol1);
// expected output: "symbol"
console.log(symbol2 === 42);
// expected output: false
console.log(symbol3.toString());
// expected output: "Symbol(foo)"
console.log(Symbol('foo') === Symbol('foo'));
// expected output: false
带有 new 运算符的语法将抛出 TypeError 错误:
var sym = new Symbol(); // TypeError
全局共享的 Symbol
创建跨文件可用的symbol,甚至跨域(每个都有它自己的全局作用域) , 使用 Symbol.for() 方法和 Symbol.keyFor() 方法从全局的symbol注册表设置和取得symbol。
对象中查找 Symbol 属性
Object.getOwnPropertySymbols() 方法让你在查找一个给定对象的符号属性时返回一个symbol类型的数组。注意,每个初始化的对象都是没有自己的symbol属性的,因此这个数组可能为空,除非你已经在对象上设置了symbol属性。
Symbols 与 JSON.stringify()
使用 JSON.stringify() 时,以 symbol 值作为键的属性会被完全忽略:
JSON.stringify({[Symbol("foo")]: "foo"});
// '{}'
Symbol 包装器对象作为属性的键
var sym = Symbol("foo");
var obj = {[sym]: 1};
obj[sym]; // 1
obj[Object(sym)]; // still 1
二、方法
1.Symbol.for(key)
方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。
Symbol.for("foo"); // 创建一个 symbol 并放入 symbol 注册表中,键为 "foo"
Symbol.for("foo"); // 从 symbol 注册表中读取键为"foo"的 symbol
Symbol.for("bar") === Symbol.for("bar"); // true,证明了上面说的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函数每次都会返回新的一个 symbol
var sym = Symbol.for("mario");
sym.toString();
// "Symbol(mario)",mario 既是该 symbol 在 symbol 注册表中的键名,又是该 symbol 自身的描述字符串
2.Symbol.keyFor(sym)
方法用来获取 symbol 注册表中与某个 symbol 关联的键。
如果全局注册表中查找到该symbol,则返回该symbol的key值,形式为string。如果symbol未在注册表中,返回undefined
// 创建一个 symbol 并放入 Symbol 注册表,key 为 "foo"
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"
// 创建一个 symbol,但不放入 symbol 注册表中
var localSym = Symbol();
Symbol.keyFor(localSym); // undefined,所以是找不到 key 的
// well-known symbol 们并不在 symbol 注册表中
Symbol.keyFor(Symbol.iterator) // undefined
3、symbol.toString();
法返回当前 symbol 对象的字符串表示。
symbol 原始值不能转换为字符串
Symbol("foo") + "bar";
// TypeError: Can't convert symbol to string
Symbol("foo").toString() + "bar"
// "Symbol(foo)bar",就相当于下面的:
Object(Symbol("foo")).toString() + "bar"
// "Symbol(foo)bar"
三、属性
1、Symbol.iterator
每一个对象定义了默认的迭代器。该迭代器可以被 for…of 循环使用。
var myIterable = {}
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
2、Symbol.match
定了匹配的是正则表达式而不是字符串。String.prototype.match() 方法会调用此函数。
禁止表达式检查
"/bar/".startsWith(/bar/);
// Throws TypeError, 因为 /bar/ 是一个正则表达式
// 且 Symbol.match 没有修改。
但是,如果你将 Symbol.match 置为 false,使用 match 属性的表达式检查会认为该象不是正则表达式对象。startsWith 和 endsWith 方法将不会抛出 TypeError。
var re = /foo/;
re[Symbol.match] = false;
"/foo/".startsWith(re); // true
"/baz/".endsWith(re); // false
3、Symbol.replace
这个属性指定了当一个字符串替换所匹配字符串时所调用的方法。String.prototype.replace() 方法会调用此方法。
class Replace1 {
constructor(value) {
this.value = value;
}
[Symbol.replace](string) {
return `s/${string}/${this.value}/g`;
}
}
console.log('foo'.replace(new Replace1('bar')));
// expected output: "s/foo/bar/g"
4、Symbol.split
指向 一个正则表达式的索引处分割字符串的方法。 这个方法通过 String.prototype.split() 调用。
class Split1 {
constructor(value) {
this.value = value;
}
[Symbol.split](string) {
const index = string.indexOf(this.value);
return `${this.value}${string.substr(0, index)}/${string.substr(index + this.value.length)}`;
}
}
console.log('foobar'.split(new Split1('foo')));
// expected output: "foo/bar"
四、作用
Symbol类型是为了解决属性名冲突的问题,顺带还具备模拟私有属性的功能。
1、命名冲突
symbol让对象的内部数据和用户数据井水不犯河水。由于sysmbol无法在 JSON 里表示,因此不用担心给 Express API 传入带有不合适的Symbol.iterator属性的数据。另外,对于那种混合了内置函数和用户数据的对象,比如 Mongoose model,你可以用symbol来确保用户数据不会跟内置属性冲突。
2、私有属性
由于任何两个symbol都是不相等的,在 JavaScript 里可以很方便地用来模拟私有属性。symbol不会出现在 Object.keys()的结果中,因此除非你明确地export 一个symbol,或者用 Object.getOwnPropertySymbols() 函数获取,否则其他代码无法访问这个属性。
function getObj() {
const symbol = Symbol('test');
const obj = {};
obj[symbol] = 'test';
return obj;
}
const obj = getObj();
Object.keys(obj); // []
// 除非有这个 symbol 的引用,否则无法访问该属性
obj[Symbol('test')]; // undefined
// 用 getOwnPropertySymbols() 依然可以拿到 symbol 的引用
const [symbol] = Object.getOwnPropertySymbols(obj);
obj[symbol]; // 'test'
还有一个原因是symbol不会出现在JSON.stringify()的结果里,确切地说是JSON.stringify()会忽略symbol属性名和属性值:
const symbol = Symbol('test');
const obj = { [symbol]: 'test', test: symbol };
JSON.stringify(obj); // "{}"
’
本文详细介绍了JavaScript中的Symbol类型,包括其概念、方法、属性和作用。Symbol用于解决属性名冲突问题,可作为私有属性使用,避免在JSON.stringify()中被序列化。
1336

被折叠的 条评论
为什么被折叠?



