【问题标题】:Why are JavaScript Symbol references safe from collisions?为什么 JavaScript 符号引用可以避免冲突?
【发布时间】:2021-04-28 19:41:58
【问题描述】:

我花了很多时间进行研究 - 我完全是个傻瓜,但我并不懒惰。我广泛使用 Reddit/SO/Google...

另外,我是在 SO 上发帖的新手,我确定我做错了什么 - 抱歉。

如果我在正确的轨道上,请告诉我:

“如果你没有符号的参考,你就不能使用它”

  • 这是否意味着您需要将符号分配给的变量作为值(在创建符号时)?那有用吗,因为该变量的范围是有限的?因此,变量范围之外的东西不会意外使用引用名称。要猜的符号没有名称,对吗?引用只是一个指针,使用指针的唯一方法是在定义指针的范围内。是这样吗?

我很困惑为什么引用不会发生冲突。我相信这与我对不同代码段如何交互的无知有关......有人不能在错误的地点/时间将我的参考作为论据,并让它与我的符号发生冲突吗?我的变量/范围是否自然无法被其他人的代码触及,还是我必须有目的地在某个特定的地方声明带有符号值的变量...呃,这是一个永无止境的兔子洞。

好吧,如果可以的话,请帮助我。如果不是,我会就下一步要潜入哪个兔子洞来接受建议。

我怀疑符号的使用会随着我“实际”使用 JavaScript 的经验而变得清晰 - 我只是将它作为第一语言学习 - 所以我所知道的只是简单/线性的 JavaScript 代码完全隔离与我未编写的任何代码进行交互。无论哪种方式,我都试图从我的立场尽可能地理解符号。

【问题讨论】:

    标签: javascript symbols


    【解决方案1】:

    混淆可能来自您对使用符号的思考方式。我会忽略与此范围相关的任何内容 - 在这方面,对符号的引用与其他变量的行为相同。

    关于你的主要问题

    “如果你没有符号的参考,你就不能使用它”

    更正确的说法是“如果您没有 * a * 符号的参考,您就不能使用它。”您不需要对符号的原始 引用,但确实需要对它的一些 引用。您不能创建与旧符号在引用上相同的符号。

    因此,如果有人引用了同一个 Symbol,您可能会遇到冲突问题,但如果没有明确公开对该符号的引用,则更难获得。

    考虑基于MDN Doc on Symbols 中所述的“主要目的”的用例:

    符号值可以用作对象属性的标识符;这是数据类型的主要用途,尽管存在其他用例,例如启用不透明数据类型,或作为一般实现支持的唯一标识符。

    // Some method you are relying on, perhaps built by a 3rd party
    const program = () => {
      // Create a symbol to use as an identifier:
      const primaryFunction = Symbol("primary");
    
      // This `obj` will be returned to the 'user' of the program below.
      const obj = {
        // This is harder (though not impossible) to access and
        // override from outside
        [primaryFunction]: (str) => {
          console.log("Run symbol function", str);
        },
        // This is relatively easy to access and
        // override from outside
        primaryFunction: (str) => {
          console.log("Run non-symbol function", str);
        }
      };
      
      // Examples of the two functions running as intended:
      obj[primaryFunction]("... first");
      obj.primaryFunction("... first");
    
      return obj;
    };
    
    // Now as a 'user' implementing `program` - get a copy of `obj` 
    const myCodeUsingProgram = program();
    
    // If I want to access the plain text key, this is trivial.
    // If I weren't paying attention, I could easily override it
    myCodeUsingProgram.primaryFunction = () => console.log("Easy to collide and break...");
    
    // Now, if I want to access Symbol key, I have to do something like this.
    // I have my own reference to the Symbol now...but I had to do some work to get it.
    // I couldn't do something like myCodeUsingProgram[Symbol("primary")]
    const newReference = Object.getOwnPropertySymbols(myCodeUsingProgram)[0];
    myCodeUsingProgram[newReference] = () => console.log("Harder to collide and break...");
    
    // Run the now 'broken' methods:
    myCodeUsingProgram.primaryFunction("... second");
    myCodeUsingProgram[newReference]("...second");

    【讨论】:

    • 我明白了...因此,在可能很关键或容易犯错误的情况下,符号被用作更难搞砸和访问/覆盖属性的一种方式。正确的?我不明白您仍然可以始终使用 getOwnPropertySymbols 获得参考(取决于有多少符号、有用的识别描述符等的情况)——这错误地使我相信符号具有特殊的不可见性以及与这种不可见性相关的用途。认为这足以让我继续前进......现在......您的示例代码非常有帮助,谢谢。
    • JavaScript 中没有多少是真正不可见或私有的。很高兴它有帮助。正如 MDN 和@Zac Anger 的回答中所指出的,Symbol 属性还有一些其他有用的案例,例如非序列化和不可枚举性。
    【解决方案2】:

    JS 符号不会发生冲突,因为每个符号都是唯一值(不是对象,符号是具有“符号”类型的原语)。当你调用Symbol('foo') 时,你没有 foo 的符号,你有一个恰好有 foo 描述的符号。这意味着:

    console.log(Symbol('foo') !== Symbol('foo')) // true
    
    const foo = Symbol('foo')
    const bar = foo;
    console.log(bar === foo) // true
    

    但是将符号作为变量传递并不是它们的真正用途,它们适用于您需要独特的东西的时候。 “如果你没有符号的参考,你就不能使用它”是正确的,不是因为范围是另一个话题,而是因为符号是独一无二的。除了您可以使用Symbol.for 查找符号,并使用Symbol.keyFor 获取您使用Symbol.for 获得的符号引用的键(描述)。

    通常您不会将符号用作函数的参数,它们的目的是用作唯一键或 ID,尤其是在您想要防止枚举或序列化或只需要您知道不会的东西的情况下作为对象中的计算属性与常规变量或字符串发生冲突(参见示例here)。

    您关于范围的其他问题与符号并不真正相关,但所有问题的答案都是:视情况而定。在过去六年(自从引入 Symbol 以来)编写的所有 JS 中,我想我用过一次或两次。如果您担心范围问题、数据或函数/方法隐私等问题,这不是答案——这些都是其他主题。

    【讨论】:

    • 谢谢,有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 2011-10-28
    • 2014-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多