Symbol 规范
MDN
es6-symbol
Symbol 基本特性
Symbol 前不能使用 new,因为其不是构造函数,是新的原始数据类型,其它的还包括(Undefined、Null、Boolean、String、Number),生成的 Symbol 是一个原始类型的值,而非对象
Symbol 的参数只是对当前 Symbol 值的描述,因此相同参数的 Symbol 函数返回值是不相等的
只接受字符串作为参数,传入其它类型时默认调用 toString() 转换, null 和 undefined 除外
Symbol 实例任何时候都是不相等的
Symbol 不能与其它类型的值运算
Symbol 值可转为布尔值和字符串,但是不能转为数值,怎么转?如下
Symbol 值作为对象属性时是公开属性
Symbol 值不允许隐式转换
Symbol 值作为属性名,不会出现在 for...in、for...of,也不能被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify() 返回,但是可以通过 Object.getOwnPropertySymbols 和 Reflect.ownKeys() 获取,所以 Symbol 定义的属性名适合作为私有属性名或方法名
typeof Symbol;
typeof Symbol();
typeof Symbol('string');
console.log(Symbol());
console.log(Symbol('string'));
Symbol(1);
Symbol(true);
Symbol(null);
Symbol(undefined);
Symbol({});
Symbol(String);
Symbol(function() {});
Symbol('s').toString();
Symbol(class);
new Symbol();
Symbol(s);
String(Symbol('s'));
Boolean(Symbol());
Number(Symbol());
'' + Symbol();
const obj = {};
const key = Symbol();
obj[key] = 'symbolValue';
const obj = {
[key]: 'symbolValue'
};
Object.defineProperty(obj, key, {
value: 'symbolValue'
});
obj.key;
Object.keys(obj);
for (let k in obj){console.log(k)}
for (let k of obj){console.log(k)}
obj[key];
Object.getOwnPropertyDescriptors(obj);
Object.getOwnPropertySymbols(obj);
Reflect.ownKeys(obj);
原型属性/方法
Object.getOwnPropertyNames(Symbol.prototype);
constructor
toString
valueOf
静态属性/方法
Object.getOwnPropertyNames(Symbol);
-
length
-
name
-
prototype
-
for 静态方法, 全局定义并在不同iframe或service worker中取到同一个值, 会去搜索已定义的值,如存在则直接返回
typeof Symbol.for;
const s1 = Symbol('for');
const s2 = Symbol('for');
s1 === s2;
iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);
iframe.contentWindow.Symbol.for('for') === Symbol.for('foo');
-
keyFor 获取 Symbol.for() 参数内容
typeof Symbol.keyFor
const s = Symbol.for('define');
Symbol.keyFor(s);
const ss = Symbol('define');
Symbol.keyFor(ss);
-
observable
-
hasInstance 对象使用instanceof判断是否为某构造函数的实例时,自动调用对象的 Symbol.hasInstance() 方法
class MyClass {
[Symbo.hasInstance](foo) {
return foo instanceof Array;
}
}
[1] instanceof new MyClass;
-
isConcatSpreadable 属性,作用于 Array.prototype.concat 时是否可以展开,默认 undefined,取值为 true 时同效
let arr1 = [1, 2, 3];
[4, 5].concat(arr1, 6);
arr1[Symbo.isConcatSpreadable];
let arr2 = [1, 2, 3];
arr2[Symbol.isConcatSpreadable] = false;
[4, 5].concat(arr2, 6);
let arg = [length: 2, 0: 1, 1: 2];
[3, 4].concat(obj, 5);
obj[Symbol.isConcatSpreadable] = true;
[3, 4].concat(obj, 5);
class A1 extends Array {
constructor(args) {
super(args);
this[Symbol.isConcatSpreadable] = true;
}
}
class A2 extends Array {
constructor(args) {
super(args);
}
get [Symbol.isConcatSpreadable]() {
return true;
}
}
let a1 = new A1();
a1[0] = 3;
a1[1] = 4;
let a2 = new A2();
a2[0] = 5;
a2[1] = 6;
[1, 2].concat(a1).concat(a2);
-
species 属性,指向当前对象的构造函数
class MyArray extends Array {
static [Symbol.species]() {
return Array;
}
}
let a = new MyArray(1,2,3);
let mapped = a.map(i => i * i);
mapped instanceof Array;
mapped instanceof MyArray;
-
match 属性,执行 str.match(myObject) 则调用
-
replace 属性,执行 String.prototype.replace 则调用
-
search 属性,执行 String.prototype.search 则调用
-
split 属性,执行 String.prototype.split 则调用
-
iterator 对象的 Symbol.iterator 属性,指向该对象的默认遍历器方法,对象进行 for...of 循环时,会调用该方法
-
toPrimitive 属性,隐式类型转换,共有3中模式: Number 需要转成数值、String 需要转成字符串、Default 该场合可以转成字符串或数值
let obj = {
[Symbol.toPrimitive](hint) {
switch(hint) {
case 'number':
return 123;
case 'string':
return 'str';
case 'default':
return 'default';
default:
throw new Error();
}
}
}
2 * obj
3 + obj
obj === 'default';
String(obj);
-
toStringTag 属性 在对象上调用 Object.prototype.toString 方法时触发,用来定制扩展 [object type]
({[Symbol.toStringTag: 'Foo'}.toString())
class Collection {
get [Symbol.toStringTag]() {
return 'XXX';
}
}
let x = new Collection();
x.toString();
Object.prototype.toString.call(x)
JSON[Symbol.toStringTag];
Math[Symbol.toStringTag];
Module对象M[Symbol.toStringTag];
ArrayBuffer.prototype[Symbol.toStringTag];
DataView.prototype[Symbol.toStringTag];
Map.prototype[Symbol.toStringTag];
Promise.prototype[Symbol.toStringTag];
Set.prototype[Symbol.toStringTag];
%TypedArray%.prototype[Symbol.toStringTag];
WeakMap.prototype[Symbol.toStringTag];
WeakSet.prototype[Symbol.toStringTag];
%MapIteratorPrototype%[Symbol.toStringTag];
%SetIteratorPrototype%[Symbol.toStringTag];
%StringIteratorPrototype%[Symbol.toStringTag];
Symbol.prototype[Symbol.toStringTag];
Generator.prototype[Symbol.toStringTag];
GeneratorFunction.prototype[Symbol.toStringTag];
-
unscopables
const symbol = Symbol('descriptor');
typeof symbol === 'symbol';
symbol;
symbol.toString();
const obj = {
toString() {
return 'toString';
}
}
const sym = Symbol(obj);
'string' + sym;
String(sym);
sym.toString();
Boolean(sym);
!sym;
Number(sym);
sym + 2;
const obj = {
[Symbol('key')]: 'symbolValue',
key: 'value'
};
Reflect.ownKeys(obj);
参考资料
Symbol Polyfill 填坑之旅