@Dale-Lin
2021-07-11T10:03:36.000000Z
字数 2687
阅读 1112
深入理解ES6
ES6 引入新的类型 Symbol。
symbol 类型属于一种基本类型。
const bar = Symbol('bar') // local symbolconst foo = Symbol.for('foo') // global symboltypeof bar // 'symbol'typeof foo // 'symbol
通过全局的 symbol 函数创建一个 Symbol:
let firstName = Symbol();let person = {};person[firstName] = "Nicholas";console.log(person[firstName]); //"Nicholas"
第一行创建了一个名为 firstName 的 Symbol。当用其作为属性名的时候,必须通过这个 Symbol 来进行访问。
Symbol 函数接受一个描述的可选参数:
let firstName = Symbol("first name");console.log(firstName); //"Symbol(first name)"
所有使用可计算属性名的地方都可以使用 Symbol:
let firstName = Symbol("first name");let person = {[firstName]: "Nicholas"};Object.defineProperty(person, firstName, {writable: false;});let lastName = Symbol("last name");Object.defineProperties(person, {[lastName]: {value: "Zakas",writable: false}});
使用 Symbol.for() 方法创建一个可共享的 Symbol:
let uid = Symbol.for("uid");let obj = {};obj[uid] = "12345";console.log(obj[uid]); //"12345"console.log(uid); //"Symbol(uid)"
Symbol.for() 方法先在全局 Symbol 注册表中搜索键为 "uid" 的 Symbol 是否存在,若存在,直接返回已存在的 Symbol;否则,创建一个新的 Symbol 并注册。
后续再传入同样的键调用 Symbol.for() 会返回相同的 Symbol:
let uid = Symbol.for("uid");let obj = {};obj[uid] = "12345";console.log(obj[uid]); //"12345"console.log(uid); //"Symbol(uid)"let uid2 = Symbol.for("uid");console.log(uid === uid2); //true
Object.keys() 和 Object.getOwnPropertyNames() 可以检索对象中所有的属性名:前一个返回所有可枚举属性名;后一个无视枚举性全部返回。但都不支持 Symbol 属性。
ES6 添加了 Object.getOwnPropertySymbols() 方法来检索对象中的 Symbol 属性,返回包含所有 Symbol 自有属性的数组:
let uid = Symbol.for("uid");let object = {[uid]: "12345"};let symbols = Object.getOwnPropertySymbols(object);console.log(symbols[length]); //1console.log(symbols[0]); //"Symbol(uid)"
Symbol.hasInstance(instance)
一个在执行 instanceof 时调用的内部方法,用于检测对象的继承信息。
每个函数中都有一个 Symbol.hasInstance(instance) 方法,用于确定对象是否为函数的实例,但默认为不可写、不可设置且不可枚举。
obj instanceof Array;
这行代码等价于:
Array[Symbol.hasInstance](obj)
ES6中可以重新定义 Symbol.hasInstance 来改变 instanceof 调用时的行为:
function MyObject() {//empty}Object.defineProperty(MyObject, Symbol.hasInstance, {value: function(instance) {return false;}});let obj = new MyObject();console.log(obj instanceof MyObject); //false
也可以用来检查:
function SpecialNumber() {//empty}Object.defineProperty(SpecialNumber, Symbol.hasInstance, {value: function(instance) {return (instance instanceof Number) && (instance >= 1 && instance <= 100);}});let two = new Number(2),zero = new Number(0);console.log(two instanceof SpecialNumber, zero instanceof SpecialNumber); //true, false
Symbol.isConcatSpreadable
Array.prototype.concat() 方法也可以接受多个包含数组的参数,并将数组分解成独立元素后拼接。
Symbol.isConcatSpreadable 属性是一个布尔值,如果该属性值为 true,则表示对象有 length 属性和数字键,故他的数值型属性值应该被独立添加到 concat() 调用的结果中:
let collection = {0: "Hello",1: "world",length: 2,[Symbol.isConcatSpreadable]: true};let message = ["Hi"].concat(collection);console.log(message); //["Hi", "Hello", "world"];
也可以在派生数组子类中将 Symbol.isConcatSpreadable 设置为 false,从而防止元素在调用 concat() 时被分解。