ES6专栏 - 新的数据结构 Symbol
目录:
-
Symbol的出现背景
-
将Symbol作为属性名
-
对Symbol属性名的遍历
-
Symbol.for(), Symbol.keyFor()
-
内置的Symbol值
Symbol的出现背景
我们在过去的开发中, 使用对象的场景由其之多, 有的时候一个对象可以很复杂, 由十多二十个属性组成, 这样对于不细心的开发者来说, 绝对会出问题, 啥问题? 哥们你没遇到过属性覆盖问题吗? 你在5天前定义了一个对象的属性name值为’loki’, 而在5天后, 你突然不小心给这个对象再次添加了一个属性name 值为thor, 自此loki就不存在了, 其实这个例子可能举得有点痴呆, 但是日常开发中我们确实有过属性覆盖从而造成bug的情况发生
于是, ES6 创造了一种新的数据结构Symbol
, 这哥们不得了, 他代表的就是一个独一无二的值, 不存在被覆盖, 如果我们用Symbol
值作为对象的属性名, 那么我们就永远不用担心覆盖的问题喽
Symbol是原始数据类型
在此之前我们知道的原始类型有: String, Number, undefined, null, Boolean, 如今又加入了一个新成Symbol, 至于object, 笔者直接把他归为引用值, 但是如果你有看过业内比较著名的《ES6标准入门》的话, 阮一峰前辈将object归类为原始值, 看自己怎么理解吧
Symbol初探
Symbol值是通过Symbol函数生成, 我们只要创建一个Symbol值出来, 他就是独一无二的
let symbolFst = Symbol('hello');
let symbolSec = Symbol('hello');
console.log(symbolFst, symbolSec); // Symbol(hello) Symbol(hello)
console.log(symbolFst === symbolSec); // false
console.log(typeof symbolFst); // symbol
即使symbolFst
和symbolSec
的值在显示上完全一致,都是Symbol(hello)
, 但实际上他们两个也是完全不同的两个个体
Symbol值虽然是通过Symbol函数生成的, 但他绝对不能使用newS操作符, 有些哥们可能会觉得Symbol函数有点构造函数的意思, 实际上并不是, 而Symbol函数所接收的参数也仅仅是给每个Symbol值加上描述, 用来做区分, 并无其他作用
当Symbol作为属性名而存在
由于Symbol值是独一无二的, 所以当Symbol值作为某个对象的key值出现的时候, 该Symbol值所代表的key也就成为了独一无二的, 当我们在merge合并的时候可以说完全不用担心某些属性会不小心被合并覆盖, 在这里我只想说: Oh my god, 用它
let obj = {
[Symbol('name')]: 'loki',
age: 18
}
let anotherObj = {
name: 'thor',
age: 19
}
let thirdObj = Object,assign({}, obj, anotherObj);
console.log(thirdObj); // {age: 19, name: "thor", Symbol(name): "loki"}
从上面的输出结果可以看得出, age值被轻易的覆盖掉了, 而Symbol值完好无损的存在
在对象中定义Symbol的几种方式
-
const obj = { [Symbol('name')]: 'loki' }
-
const obj = {}; obj[Symbol('name')] = 'loki'
-
const obj = {}; Object.defineProperty(obj, Symbol('name'), { value: 'loki' })
Symbol属性名的遍历
Symbol作为属性名, 以下方法并不能正常检索到这哥们
- for…in
const obj = {
[Symbol('name')]: 'loki',
age: 18,
sex: 'male'
}
for(let prop in obj) {
console.log(prop);
}
// 只会输出 age , sex
- Object.keys(), Object.values(), Object.entries()
const obj = {
[Symbol('name')]: 'loki',
age: 18,
sex: 'male'
}
console.log(Object.keys(obj)); // ["age", "sex"]
console.log(Object,values(obj)); // [18, "male"]
- Object.getOwnPropertyNames()
const obj = {
[Symbol('name')]: 'loki',
age: 18,
sex: 'male'
}
console.log(Object.getOwnPropertyNames(obj)); // ["age", "sex"]
那么我们如果想要拿到Symbol属性怎么办呢, ES6给我们提供了新的api来帮助我们找到某个对象下的所有Symbol属性, 跑不掉的
- Object.getOwnPropertySymbols()
const obj = {
[Symbol('name')]: 'loki',
age: 18,
sex: 'male'
}
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(name)]
- Reflect.ownKeys()
const obj = {
[Symbol('name')]: 'loki',
age: 18,
sex: 'male'
}
console.log(Reflect.ownKeys(obj)); // ["age", "sex", Symbol(name)]
Symbol.for(), Symbol.keyFor()
Symbol.for
现在我给你提个需求, 我要你给我直接每次创建的同描述Symbol都是第一次创建的那哥们, 你会说简单, 直接取拿值存储就好了
let getSingleSymbol = (function() {
let name = null
return function (str) {
if(!name) name = Symbol('name');
return name;
}
}())
let fstName = getSingleSymbol('name');
let secName = getSingleSymbol('name');
console.log(fstName === secName, fstName, secName); // true Symbol(name) Symbol(name)
确实我们可以通过上面这种封装一个函数来拿到单例single, 但是其实Es6给我们提供了一种更加简便的方法Symbol.for(str)
let fstName = Symbol.for('name');
let secName = Symbol.for('name');
console.log(fstName === secName, fstName, secName); // true Symbol(name) Symbol(name)
Symbol.for实现的功能跟我写的第一个getSingleSymbol效果是一致的
Symbol.keyFor
实际上, 上方的Symbol.for他的单例形成值还不是跟我们一样存放在一个变量中, 而是存放在一个Symbol注册表中, 当我们每次Symbol.for创建一个Symbol值, 该Symbol值的描述就会被存储进这个Symbol注册表中, 而我们通过Symbol.keyFor就可以知道这个表中有没有我们当前创建的这个Symbol值的描述, 可以避免不必要的麻烦
话不多说直接上代码
const fstSymbol = Symbol.for('name');
const secSymbol = Symbol('age');
let trdSymbol = null;
if(Symbol.keyFor(fstSymbol)) {
trdSymbol = Symbol.for('name2');
}
console.log(Symbol.keyFor(fstSymbol)); // name
console.log(Symbol.keyFor(secSymbol)); // undefined
这哥们其实就是用来防止Symbol描述重复导致创建不出自己想要的Symbol值的, 反正笔者至今没用过一次0.0
内置的Symbol值
这个笔者打算今年夏天研究, 所以不是很懂 ~ 这些值指向一些系统的底层方法, 比如Symbol.split, Symbol.hasInstance, Symbol.match 等
至此, 笔者所了解的Symbol已经全部写完, 希望对你可以产生帮助, 我也希望我讲清楚了
来源:CSDN
作者:付金权
链接:https://blog.csdn.net/weixin_44238796/article/details/104643662