ES6高级特性--Symbol
Posted Nicolas Shawn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6高级特性--Symbol相关的知识,希望对你有一定的参考价值。
Symbol
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 javascript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)
# 简单使用
let s = Symbol();
typeof s
// "symbol"
# 接受字符串作为参数
let s1 = Symbol(\'foo\');
let s2 = Symbol(\'bar\');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
String(s1)
# 可以使用toString()方法
const obj = {
toString() {
return \'abc\';
}
};
const sym = Symbol(obj);
sym // Symbol(abc)
# 相同的参数值是不相等的
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol(\'foo\');
let s2 = Symbol(\'foo\');
s1 === s2 // false
# 无法参与运算
let sym = Symbol(\'My symbol\');
"your symbol is " + sym
// TypeError: can\'t convert symbol to string
`your symbol is ${sym}`
// TypeError: can\'t convert symbol to string
# Symbol 值可以显式转为字符串、布尔值、但是不能转为数字
let sym = Symbol(\'My symbol\');
String(sym) // \'Symbol(My symbol)\'
sym.toString() // \'Symbol(My symbol)\'
let sym = Symbol();
Boolean(sym) // true
!sym // false
if (sym) {
// ...
}
Number(sym) // TypeError
sym + 2 // TypeError
# 作为属性名的symbol
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = \'Hello!\';
// 第二种写法
let a = {
[mySymbol]: \'Hello!\'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: \'Hello!\' });
// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
# 注意,Symbol 值作为对象属性名时,不能用点运算符。
const mySymbol = Symbol();
const a = {};
a.mySymbol = \'Hello!\';
a[mySymbol] // undefined
a[\'mySymbol\'] // "Hello!"
let s = Symbol();
let obj = {
[s]: function (arg) { ... }
};
obj[s](123);
// ==> 使用对象增强法更简洁的写法:
let obj = {
[s](arg) { ... }
};
Symbol应用场景
# 场景一:常量定义
const log = {};
log.levels = {
DEBUG: Symbol(\'debug\'),
INFO: Symbol(\'info\'),
WARN: Symbol(\'warn\')
};
console.log(log.levels.DEBUG, \'debug message\');
console.log(log.levels.INFO, \'info message\');
// 定义常量 场景2
const COLOR_RED = Symbol();
const COLOR_GREEN = Symbol();
function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_GREEN;
case COLOR_GREEN:
return COLOR_RED;
default:
throw new Error(\'Undefined color\');
}
}
# 场景二:消除魔术字符串
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 });
// 使用symbol 替换如下:
const shapeType = {
triangle: Symbol()
};
# 场景3:
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)]
// 用例2
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)]
// 新的 API,Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
let obj = {
[Symbol(\'my_key\')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
// Symbol 值作为键名,不会被常规方法遍历得到。我们可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
let size = Symbol(\'size\');
class Collection {
constructor() {
this[size] = 0;
}
add(item) {
this[this[size]] = item;
this[size]++;
}
static sizeOf(instance) {
return instance[size];
}
}
let x = new Collection();
Collection.sizeOf(x) // 0
x.add(\'foo\');
Collection.sizeOf(x) // 1
Object.keys(x) // [\'0\']
Object.getOwnPropertyNames(x) // [\'0\']
Object.getOwnPropertySymbols(x) // [Symbol(size)]
// 以上这段代码,对象x的size属性是一个 Symbol 值,所以Object.keys(x)、Object.getOwnPropertyNames(x)都无法获取它。这就造成了一种非私有的内部方法的效果。
Symbol.for(),Symbol.keyFor()
# 有时,我们希望重新使用同一个Symbol值 Symbol.for()
let s1 = Symbol.for(\'foo\');
let s2 = Symbol.for(\'foo\');
s1 === s2 // true
// 问题:Symbol.for()与Symbol()有啥区别?
// 前者会被登记在全局环境中供搜索,后者不会。
Symbol.for("bar") === Symbol.for("bar")
Symbol("bar") === Symbol("bar")
# Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
// I*Symbol.for()为 Symbol 值登记的名字,是全局环境的,不管有没有在全局环境运行。
function foo() {
return Symbol.for(\'bar\');
}
const x = foo();
const y = Symbol.for(\'bar\');
console.log(x === y); // true
以上是关于ES6高级特性--Symbol的主要内容,如果未能解决你的问题,请参考以下文章