新的原始数据类型Symbol,表示独一无二的值,是javascript的第七种数据类型。前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
注意事项:
1、Symbol函数前不能使用new命令,否则会报错。由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。 Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述。
let s1 = Symbol('foo');
let s2 = Symbol('bar');
console.log(s1) // Symbol(foo)
console.log(s1.toString()) // Symbol(foo)
2
3
4
2、如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。
const obj = {
toString() {
return 'abc';
}
};
const sym = Symbol(obj);
console.log(sym) // Symbol(abc)
2
3
4
5
6
7
3、Symbol函数的参数只是表示对当前
Symbol
值的描述,因此相同参数的Symbol函数的返回值是不相等的。
// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
2
3
4
5
6
7
8
4、Symbol 值不能与其他类型的值进行运算,会报错。
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
2
3
4
5
5、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
Console.log(sym + 2) // TypeError
2
3
4
5
6
7
8
9
# Symbol的常见用法
1、 作为属性名
Symbol 值作为对象属性名时,不能用点运算符。一般使用方括号。
const mySymbol = Symbol();
const a = {};
a.mySymbol = 'Hello!';//此处的mySymbol只能看成是字符串,而不能看成是一个Symbol值
console.log(a[mySymbol]) // undefined
consoe.log(a['mySymbol']) // "Hello!"
2
3
4
5
在对象的内部,使用 Symbol
值定义属性时,Symbol
值必须放在方括号之中。
let s = Symbol();
let obj = {
[s]: function (arg) { ... }
};
obj[s](123);
2
3
4
5
Symbol
类型还可以用于定义一组常量,保证这组常量的值都是不相等的。Symbol
值作为属性名时,该属性还是公开属性,不是私有属性。
魔术字符串:在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。利用Symbol
来消除。
const shapeType = {
triangle: Symbol('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 });
2
3
4
5
6
7
8
9
10
11
12
13
14
2、 属性名的遍历
Symbol 作为属性名,该属性不会出现在for...in、for...of
循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()
返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols
方法,可以获取指定对象的所有 Symbol
属性名。可以利用这个特性,为对象定义一些非私有的、但又希望只用于内部的方法。
3、 Symbol.for()、Symbol.keyFor()
Symbol.for("foo"): 接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol
值。如果有,就返回这个 Symbol
值,否则就新建并返回一个以该字符串为名称的 Symbol
值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
console.log(s1 === s2) // true
2
3
Symbol.keyFor: 返回一个已登记的 Symbol
类型值的key
。返回一个使用Symbol.for()
方法定义的key。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
2
3
4
注意:Symbol.for
为 Symbol
值登记的名字,是全局环境的,可以在不同的 iframe
或 service worker
中取到同一个值。
4、 内置的Symbol值
Symbol.hasInstance: 对象的Symbol.hasInstance
属性,指向一个内部方法。当其他对象使用instanceof
运算符,判断是否为该对象的实例时,会调用这个方法。比如,foo instanceof Foo
在语言内部,实际调用的是Foo[Symbol.hasInstance](foo)
。
class MyClass {
[Symbol.hasInstance](foo) {
return foo instanceof Array;
}
}
console.log([1, 2, 3] instanceof new MyClass()) // true
2
3
4
5
6
Symbol.isConcatSpreadable: 等于一个布尔值,表示该对象用于Array.prototype.concat()
时,是否可以展开。
let arr1 = ['c', 'd'];
['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
arr1[Symbol.isConcatSpreadable] // undefined
let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']
2
3
4
5
6
类似数组的对象正好相反,默认不展开。它的Symbol.isConcatSpreadable
属性设为true,才可以展开。
let obj = {length: 2, 0: 'c', 1: 'd'};
['a', 'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']
obj[Symbol.isConcatSpreadable] = true;
['a', 'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']
2
3
4
Symbol.species: 指向一个构造函数。创建衍生对象时,会使用该属性。下面例子中b、c是a的衍生对象。
class MyArray extends Array {
static get [Symbol.species]() { return Array; }
}
const a = new MyArray(1, 2, 3);
const b = a.map(x => x);
const c = a.filter(x => x > 1);
b instanceof MyArray // false
b instanceof Array //true
c instanceof MyArray // false
2
3
4
5
6
7
8
9
主要的用途: 有些类库是在基类的基础上修改的,那么子类使用继承的方法时,作者可能希望返回基类的实例,而不是子类的实例。
还有其他属性就不一一例举了:Symbol.match、Symbol.replace、Symbol.search、Symbol.split、Symbol.iterator、Symbol.toPrimitive、Symbol.toStringTag(toString())、Symbol.unscopables(with)