zoukankan      html  css  js  c++  java
  • 【Vue源码相关】[ES6]Symbol属性及其作用

    在 symbols 诞生之前,对象的键只能是字符串。假如我们试着使用一个非字符串当做对象的键,就会被转换为字符串,如下所示:

    const obj = {};
    obj.foo = 'foo';
    obj['bar'] = 'bar';
    obj[2] = 2;
    obj[{}] = 'someobj';
    console.log(obj);
    // { '2': 2, foo: 'foo', bar: 'bar', '[object Object]': 'someobj' }

    symbols 是什么?

    • symbols 是一种无法被重建的基本类型。这时 symbols 有点类似与对象创建的实例互相不相等的情况,但同时 symbols 又是一种无法被改变的基本类型数据。
    const s1 = Symbol();
    const s2 = Symbol();
    console.log(s1 === s2); // false

    当你初始化一个带有一个接收可选字符串参数的 symbols 时,我们可以来看下,除此之外看看它会否影响自身。

    const s1 = Symbol('debug');
    const str = 'debug';
    const s2 = Symbol('xxyy');
    console.log(s1 === str); // false
    console.log(s1 === s2); // false
    console.log(s1); // Symbol(debug)

    symbols 作为对象的属性

    • symbols 有另一个很重要的用途,就是用作对象的 key。这儿有一个 symbols 作为对象 key 使用的例子:
    const obj = {};
    const sym = Symbol();
    obj[sym] = 'foo';
    obj.bar = 'bar';
    console.log(obj); // { bar: 'bar' }
    console.log(sym in obj); // true
    console.log(obj[sym]); // foo
    console.log(Object.keys(obj)); // ['bar']
    • 我们注意到使用 Object.keys() 并没有返回 symbols,这是为了向后兼容性的考虑。老代码不兼容 symbols,因此古老的 Object.keys() 不应该返回 symbols。

    • 看第一眼,我们可能会觉得 symbols 这个特性很适合作为对象的私有属性,许多其他语言都要类似的类的隐藏属性,这一直被认为是 JavaScript 的一大短板。不幸的是,还是有可能通过 symbols 来取到对象的值,甚至都不用试着获取对象属性就可以得到对象 key,例如,通过 Reflect.ownKeys() 方法就可以获取所有的 key,包括 字符串和 symbols,如下所示:

    function tryToAddPrivate(o) {
      o[Symbol('Pseudo Private')] = 42;
    }
    const obj = { prop: 'hello' };
    tryToAddPrivate(obj);
    console.log(Reflect.ownKeys(obj));// [ 'prop', Symbol(Pseudo Private) ]
    console.log(obj[Reflect.ownKeys(obj)[1]]); // 42
    注意:现在已经有一个旨在解决 JavaScript 私有属性的提案,叫做 Private Fields,尽管这并不会使所有的对象受益,它仍然对对象的实例有用,Private Fields 在 Chrome 74版本可用。

    阻止对象属性名冲突

    • symbols 可能对对象的私有属性没有直接好处,但是它有另外一个用途,它在不知道对象原有属性名的情况下,扩展对象属性很有用。
    • 考虑一下当两个不同的库要读取对象的一些原始属性时,或许它们都想要类似的标识符。如果只是简单的使用字符串 id 作为 key,这将会有很大的风险,因为它们的 key 完全有可能相同。
    function lib1tag(obj) {
      obj.id = 42;
    }
    function lib2tag(obj) {
      obj.id = 369;
    }

    通过使用 symbols,不同的库在初始化的时候生成其所需的 symbols,然后就可以在对象上任意赋值。

    const library1property = Symbol('lib1');
    function lib1tag(obj) {
      obj[library1property] = 42;
    }
    const library2property = Symbol('lib2');
    function lib2tag(obj) {
      obj[library2property] = 369;
    }

    这方面 symbols 的确对 JavaScript 有用。然后你或许会奇怪,不同的库进行初始化的时候为什么不使用随机字符串,或者使用命名空间呢?

    const library1property = uuid(); // random approach
    function lib1tag(obj) {
      obj[library1property] = 42;
    }
    const library2property = 'LIB2-NAMESPACE-id'; // namespaced approach
    function lib2tag(obj) {
      obj[library2property] = 369;
    }
    • 你是对的,这种方法确实类似于 symbols 的这一作用,除非两个库使用相同的属性名,那就会有被覆写的风险。但是仍然有一点细微的不同,字符串是不可变的,而 symbols 可以保证永远唯一,因此仍然有可能会有人生成重名的字符串。从数学意义上 symbols 提供了一个字符串没有的优点。

    • 机敏的读者已经发现这两种方案的效果并不完全相同。我们独有的属性名仍然有一个缺点:它们的 key 很容易被找到,尤其是当代码进行递归或者序列化对象,考虑如下的例子:

    const library2property = 'LIB2-NAMESPACE-id'; // namespaced
    function lib2tag(obj) {
      obj[library2property] = 369;
    }
    const user = {
      name: 'Thomas Hunter II',
      age: 32
    };
    lib2tag(user);
    JSON.stringify(user);
    // '{"name":"Thomas Hunter II","age":32,"LIB2-NAMESPACE-id":369}'
    • 假如我们使用 symbols 作为属性名,json 的输出将不会包含 symbols,这是为什么呢?因为 JavaScript 支持 symbols,并不意味着 json 规范也会跟着修改。json 只允许字符串作为 key,JavaScript 并没有试图让 json 输出 symbols。

    转自:https://blog.csdn.net/weixin_34124939/article/details/91456169

  • 相关阅读:
    百度面试题:把数组排成最小的数
    面试题:在O(1)时间删除链表结点
    从第一字符串中删除第二个字符串中所有的字符
    在一个字符串中找到第一个只出现一次的字符
    大整数运算
    输出1到最大的N位数
    删除字符串中的数字并压缩字符串
    排列 或组合问题的解法(包含回溯法)
    卡特兰数(Catalan)简介
    编程之美-分层遍历二叉树
  • 原文地址:https://www.cnblogs.com/vickylinj/p/13037892.html
Copyright © 2011-2022 走看看