文章目录 1、简介2、description()方法3、Symbol类型的应用给对象内追加属性消除魔术字符串 4、symbol属性名的遍历方法5、其他方法Symbol.for()Symbol.keyFor()1、简介
Symbol类型主要是用于保证值是独一无二的,是一种类似于字符串的数据类型,它是 JavaScript 语言的第七种数据类型。
Symbol 值通过Symbol
函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
for...in
、for...of
循环中Symbol值不能用来做运算
语法:
// 没有描述符的symbol值
let s = Symbol();
// 有描述符的symbol值
let s1 = Symbol('hello');
console.log(s, s1); //Symbol() Symbol(hello)
console.log(typeof s); //symbol
无论symbol带不带参数,它都是独一无二的值,例如:
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
2、description()方法
Symbol.prototype.description
用于获取对Symbol类型的描述。创建Symbol的时候,可以添加一个描述,ES2019 提供了一个实例属性description
,直接返回 Symbol 的描述。如果没有描述则返回undefined。
const sym = Symbol('foo');
sym.description // "foo"
3、Symbol类型的应用
给对象内追加属性
假设有一个obj内部的属性都是不可枚举属性,不动其他属性的情况下,现需要在obj内放一个值’张三’,属性名无所谓。你知道obj对象内有什么属性吗?肯定不知道对不对,好,那现在往对象里添加一个属性,值为’张三’,你敢添加吗?假设你要添加的属性名是name,那么会出现两种情况,要么obj内没有name属性,你添加成功,要么obj内有name属性,你覆盖了人家原来的值。这时候symbol的作用就出来了。
let obj = {
// ...此处省略n多个属性
name: 'ronda'
};
// 因为symbol是独一无二的,那么属性名就可以用symbol来表示。
let tempName = Symbol('name');
obj[tempName] = '张三'; // '张三'保存到了obj对象中
console.log(obj[tempName]); //张三
console.log(obj); //{ name: 'ronda',[Symbol(name)]:'张三' }
//声明一个对象,里面存方法
let methods = {
up: Symbol(),
down:Symbol()
};
obj[methods.up] = function(){
console.log("向上");
}
obj[methods.down] = function(){
console.log("向下");
}
console.log(obj);
这里symbol的作用就是防止覆盖相同属性名的值。
let game = {
name:"狼人杀",
[Symbol('say')]:function(){
console.log("说话");
},
[Symbol('explode')]:function(){
console.log('爆炸');
}
}
console.log(game); //
消除魔术字符串
魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
代码耦合:一个软件结构内不同模块之间互连程度的度量(耦合性也叫块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差,模块间耦合的高低取决于模块间接口的复杂性,调用的方式以及传递的信息。
例一:
function getArea(shape, options) {
let area = 0;
switch (shape) {
case 'Triangle': // 魔术字符串
area = .5 * options.width * options.height;
break;
/* ... more code ... */
}
return area;
}
getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串
上述代码重Triangle字符串重复出现,所以是魔术字符串,可以通过将这个字符串写在一个对象里面,这是一种解决方式,如下:
const shapeType = { triangle: 'Triangle' }; function getArea(shape, options) { let area = 0; switch (shape) { case shapeType.triangle: area = .5 * options.width * options.height; break; } return area; } getArea(shapeType.triangle, { width: 100, height: 100 });
这样做就消除了强耦合,再次仔细分析,可以发现
shapeType.triangle
等于哪个值并不重要,只要确保不会跟其他shapeType
属性的值冲突即可。因此,这里就很适合改用 Symbol 值。const shapeType = { triangle: Symbol() }; function getArea(shape, options) { let area = 0; switch (shape) { case shapeType.triangle: area = .5 * options.width * options.height; break; } return area; } getArea(shapeType.triangle, { width: 100, height: 100 });
例2:结合switch使用
let obj = {
attr1: Symbol('one'),
attr2: Symbol('two'),
attr3: Symbol('three'),
attr4: Symbol('four'),
};
function test(param) {
switch (param) {
case obj.attr1:
console.log('这是one的 *** 作');
break;
case obj.attr2:
console.log('这是two的 *** 作');
break;
case obj.attr3:
console.log('这是three的 *** 作');
break;
case obj.attr4:
console.log('这是four的 *** 作');
break;
default:
console.log('这是默认的 *** 作');
break;
}
}
test(obj.attr1); //这是one的 *** 作
4、symbol属性名的遍历方法
Symbol 作为属性名,遍历对象的时候,该属性不会出现在
for...in
、for...of
循环中,也不会被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols()
方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
例一:
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]
例二:使用getOwnPropertySymbol()方法和for…in、Object.getOwnPropertyNames()进行对比
const obj = {};
const foo = Symbol('foo');
obj[foo] = 'bar';
for (let i in obj) {
console.log(i); // 无输出
}
Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [Symbol(foo)]
5、其他方法 Symbol.for()此外,
Reflect.ownKeys()
方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。let obj = { [Symbol('my_key')]: 1, enum: 2, nonEnum: 3 }; Reflect.ownKeys(obj); // ["enum", "nonEnum", Symbol(my_key)]
Symbol.for(key) 方法会根据给定的键 key,来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的symbol对象,并放入全局 symbol 注册表中。
语法:
Symbol.for(key);
参数:
key 一个字符串,作为 symbol 注册表中与某 symbol 关联的键(同时也会作为该 symbol 的描述)。
返回值:
返回由给定的 key 找到的 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
let sym = Symbol.for("mario");
sym.toString();
// "Symbol(mario)",mario 既是该 symbol 在 symbol 注册表中的键名,又是该 symbol 自身的描述字符串,为了防止冲突,最好给要放入 symbol 注册表中的 symbol 带上键前缀。
Symbol.for("mdn.foo");
Symbol.for("mdn.bar");
Symbol.keyFor()
Symbol.keyFor(sym) 方法用来获取全局symbol 注册表中与某个 symbol 关联的键。返回一个已登记的 Symbol 类型值的key。
语法:
Symbol.keyFor(sym);
参数:
sym 必选参数,需要查找键值的某个 Symbol 。
返回值:
如果全局注册表中查找到该symbol,则返回该symbol的key值,返回值为字符串类型。否则返回undefined。
// 创建一个全局 Symbol
let globalSym = Symbol.for("foo");
console.log(Symbol.keyFor(globalSym)); // "foo"
let localSym = Symbol();
console.log(Symbol.keyFor(localSym)); // undefined
// 以下Symbol不是保存在全局Symbol注册表中
console.log(Symbol.keyFor(Symbol.iterator)); // undefined
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)