ES6专栏 - 新的数据结构 Symbol

人走茶凉 提交于 2020-03-04 23:41:04

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

即使symbolFstsymbolSec的值在显示上完全一致,都是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已经全部写完, 希望对你可以产生帮助, 我也希望我讲清楚了

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!