创建符号值
Symbol没有字面量形式,这在JS的基本类型中是独一无二的.可以用全局函数来创建符号值
let firstName=Symbol();
let person={};
person[firstName]='Polo';
console.log(person[firstName]); // 'Polo'
//es6扩展了typeof运算符,可以识别symbol基本类型
console.log(typeof firstName); // 'symbol;
符号值是基本类型,因此调用new Symbol()会抛出错误
共享符号值
使用Symbol.for方法,创建共享符号值,该方法仅接受当字符串类型的参数,作为目标符号值得标识符,同时此参数也会成为该符号的描述信息
let uid=Symbol.for('uid');
let obj={};
obj[uid]=12334;
console.log(obj[uid]); // 12334
console.log(uid); // symbol(uid)
Symbol.for() 方法首先会搜索全局符号注册表,看是否存在一个键值为 "uid" 的符号值。若是,该方法会返回这个已存在的符号值;否则,会创建一个新的符号值,并使用该键值将其记录到全局符号注册表中,然后返回这个新的符号值。这就意味着此后使用同一个键值去调用 Symbol.for() 方法都将会返回同一个符号值,就像下面这个例子:
let uid=Symbol.for('uid');
let obj={};
obj[uid]=12334;
let uid2=Symbol.for('uid');
console.log(uid===uid2); //true
console.log(obj[uid2]); //12334
console.log(uid2); //symbol(uid)
Symbol.keyFor方法,在全局符号注册表中根据符号值检索出对应的键值
let uid = Symbol.for("uid");
console.log(Symbol.keyFor(uid)); // "uid"
检索符号属性
Object.keys()返回对象所有可枚举属性名称
Object.getOwnPropertyNames() 返回所有属性名称而无视其是否可枚举
然而以上两个方法都不能返回符号类型的属性,
ES6中新增Object.getOwnPropertySymbols(),返回符号类型的属性
ES6知名符号
ES6 定义了“知名符号”来代表 JS 中一些公共行为,而这些行为此前被认为只能是内部操作。每一个知名符号都对应全局 Symbol 对象的一个属性
这些知名符号是:
- Symbol.hasInstance :供 instanceof 运算符使用的一个方法,用于判断对象继承关系。
- Symbol.isConcatSpreadable :一个布尔类型值,在集合对象作为参数传递给
- Array.prototype.concat() 方法时,指示是否要将该集合的元素扁平化。
- Symbol.iterator :返回迭代器(参阅第七章)的一个方法。
- Symbol.match :供 String.prototype.match() 函数使用的一个方法,用于比较字符串。
- Symbol.replace :供 String.prototype.replace() 函数使用的一个方法,用于替换子字符串。
- Symbol.search :供 String.prototype.search() 函数使用的一个方法,用于定位子字符串。
- Symbol.species :用于产生派生对象(参阅第八章)的构造器。
- Symbol.split :供 String.prototype.split() 函数使用的一个方法,用于分割字符串。
- Symbol.toPrimitive :返回对象所对应的基本类型值的一个方法。
- Symbol.toStringTag :供 String.prototype.toString() 函数使用的一个方法,用于创建对象的描述信息。
- Symbol.unscopables :一个对象,该对象的属性指示了哪些属性名不允许被包含在 with 语句中。
Symbol.hasInstance
用于判断指定对象是否为本函数的一个实例。这个方法定义在 Function.prototype 上,因此所有函数都继承了面对 instanceof 运算符时的默认行为。 Symbol.hasInstance 属性自身是不可写入、不可配置、不可枚举的,从而保证它不会被错误地重写。
obj instanceof Array;
//等价于
Array[Symbol.hasInstance](obj);
ES6 从本质上将 instanceof 运算符重定义为上述方法调用的简写语法.
例如,假设你想定义一个函数,使得任意对象都不会被判断为该函数的一个实例,你可以采用硬编码的方式让该函数的 Symbol.hasInstance 方法始终返回 false
function MyObj(){
}
Object.defineProperty(MyObj,Symbol.hasInstance,{
value:function(v){
return false;
}
});
let obj=new MyObj();
console.log(obj instanceof MyObj); // false
Symbol.isConcatSpreadable
该属性是一个布尔类型的属性,它表示目标对象拥有长度属性与数值类型的键、并且数值类型键所对应的属性值在参与 concat() 调用时需要被分离为个体。它只出现在特定类型的对象上,用来标示该对象在作为 concat() 参数时应如何工作,从而有效改变该对象的默认行为。
let collection = {
0: "Hello",
1: "world",
length: 2,
[Symbol.isConcatSpreadable]: true
};
let messages = [ "Hi" ].concat(collection);
console.log(messages.length); // 3
console.log(messages); // ["hi","Hello","world"]
Symbol.toPrimitive
该属性规定了在对象被转换为基本类型值的时候会发生什么。
当需要转换时, Symbol.toPrimitive 会被调用,并按照规范传入一个提示性的字符串参数。该参数有 3 种可能:
- 当参数值为 "number" 的时候, Symbol.toPrimitive 应当返回一个数值;
- 当参数值为 "string" 的时候,应当返回一个字符串;
- 而当参数为 "default" 的时候,对返回值类型没有特别要求。
function Temperature(degrees) {
this.degrees = degrees;
}
Temperature.prototype[Symbol.toPrimitive] = function(hint) {
switch (hint) {
case "string":
return this.degrees + "\u00b0"; // 温度符号
case "number":
return this.degrees;
case "default":
return this.degrees + " degrees";
}
};
let freezing = new Temperature(32);
console.log(freezing + "!"); // "32 degrees!"
console.log(freezing / 2); // 16
console.log(String(freezing)); // "32°"
Symbol.toStringTag
该属性定义了Object.prototype.toString.call()被调用时应该返回什么值,同样可以在自定义对象上定该属性值.
function Person(name) {
this.name = name;
}
Person.prototype[Symbol.toStringTag] = "Person";
let me = new Person("Nicholas");
console.log(me.toString()); // "[object Person]"
console.log(Object.prototype.toString.call(me)); // "[object Person]"