Symbol和Symbol属性
第6
种原始数据类型:Symbol
。私有名称原本是为了让开发者们创建非字符串属性名称而设计的,但是一般的技术无法检测这些属性的私有名称
创建Symbol
let firstName = Symbol();
let person = {}
person[firstName] = "Nicholas";
console.log(person[firstName]); // Nicholas
new Symbol()
会报错,Symbol函数接受一个可选参数,其可以让你添加一段文本描述即将创建的Symbol,这段描述不可用于属性访问,但是建议你在每次创建Symbol时都添加一段描述,以便于阅读代码和调试Symbol程序
let firstName = Symbol('first name');
let person = {}
person[firstName] = "Nicholas"
console.log("first name" in person); // false
console.log(person[firstName]); //Nicholas
console.log(firstName) // "Symbol(first name)"
Symbol的描述被存储在内部的[[Description]]
属性中,只有当调用Symbol的toString()方法才可以读取这个属性,在执行console.log时,隐式调用了firstName的toString()方法,所以它的描述会被打印到日志中,但是不能直接在代码里访问[[Description]]
。
使用typeof symbol 如果是会返回'symbol',所有使用计算属性名的地方,都可以使用Symbol。
Symbol的使用方法
我们之前都是在括号中使用Symbol,事实上,Symbol也可以用于可计算对象字面量属性、Object.defineProperty()
方法和Object.defineProperties()
方法的调用过程
let fristName = 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
}
})
console.log(person[firstName]) //Nicholas
console.log(person[lastName]) //Zakas
虽然在所有使用可计算属性名的地方,都可以使用Symbol来替代,但是为了在不同的代码片段间有效地共享这些Symbol,需要建立一个体系
Symbol共享体系
例如我们想在不同的对象类型,想使用同一个Symbol属性来表示一个独特的标识符。在很大的代码库或跨文件追踪Symbol非常困难且容易出错,出于这些原因ES6提供了一个可以随时访问全局Symbol注册表。使用Symbol.for(xxx)
只接受一个参数。要创建Symbol的字符串描述类似Symbol('xxx')
。 Symbol.for(xxx)
会去全局注册表中找有没有注册这个Symbol,有就返回,没有就创建一个并注册到全局表中,下次不用再新建一个了。
Symbol与类型转换
我上面的示例使用console.log()
方法来输出Symbol
的内容,它会调用Symbol的String()方法输出有用信息,如果你试图将一个Symbol和一个字符串拼接,会导致程序抛出错误。
let uid = Symbol.for("uid"),
desc = String(uid);
console.log(desc); // Symbol(uid)
Symbol的属性检索
Object.keys()
和Object.getOwnPropertyNames()
方法可以检索对象中所有的属性名,后一个方法不考虑属性的可枚举性一律返回。这两个方法都支持Symbol属性。所以又推出了一个Object.getOwnPropertySymbols()
方法返回一个包含所有Symbole自有属性的值。
let uid = Symbol.for("uid");
let object = {
[uid]:"12345"
}
let symbols = Object.getOwnPropertySymbols(object);
console.log(symbols.length) // 1
console.log(symbols[0]) // "Symbol(uid)"
console.log(object[symbols[0]]) //12345
通过well-know Symbol暴露内部操作
Symbol.hasInstance
Symbol.isConcatSpreadable
Symbol.iterator
Symbol.match
Symbol.replace
Symbol.species
Symbol.split
Symbol.species
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables
obj instanceof Array;
// 等价于
Array[Symbol.hasInstance](obj)
// 本质上,es6只是将instanceof操作符重新定义为此方法的简写语法,现在引入调用后,就可以随意改变instanceof的运行方式了。
// 假设你想定义一个无实例的函数,就可以将Symbol.hasInstance的返回值硬编码为false
function MyObject(){
// 空函数
}
Object.defindProperty(MyObject,Symbol.hasInstance,{
value:function(v){
return false
}
})
let obj = new MyObject()
console.log(obj instanceof MyObject) // false
Symbol.isConcatSpreadable
js数组的concat
方法被设计用于拼接两个数组,使用如下方法:
let color1 =["red","green"],
color2 = color1.concat(["blue","black"])
console.log(color2.length) // 4
console.log(color2) // ["red","green","blue","black"]
// color1与一个临时数组拼接成两个数组
// concat方法也可以接受非数组参数,此时该方法只会将这些参数逐一添加到数组末尾如下
let color1 =["red","green"],
color2 = color1.concat(["blue","black"],"brown")
console.log(color2.length) // 5
console.log(color2) // ["red","green","blue","black","brown"]
// 这个属性可以设置或阻止调用concat方法时是否展开
主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://joyjs.cn/archives/4332