【问题标题】:Object and primitive type equality对象和原始类型相等
【发布时间】:2014-01-31 19:21:47
【问题描述】:

我知道相同的对象不相等,即:

var obj = { name: "Value" };
var obj2 = { name: "Value" };

console.log("obj equals obj2: " + (obj === obj2)); //evaluates to false

然而原始类型是:

var str = "string1";
var str2 = "string1";

console.log("str equals str2: " + (str === str2)); //evaluates to true

我的问题是为什么。为什么对象和基元的处理方式不同?如果一个对象只是一个空容器,只有您指定放入容器中的属性,为什么容器的相同属性评估结果不一样?我在 SO 和其他地方四处寻找这个答案,但没有找到答案。

JS 对象在 DOM 中是否被视为不同于原始类型的东西?

谢谢

【问题讨论】:

  • 您询问语言的实现,所以我不确定,但想象一下必须对比较的每个对象的每个字段进行内部检查,然后必须定义什么是完全相等的.我猜设计师决定将对象的这种相等性留给程序员。

标签: javascript object equality primitive


【解决方案1】:

这似乎真的是一个关于=== 的问题,所以让我们看看the Strict Equality Comparison Algorithm,其中第 7 点说

如果 x 和 y 引用 同一个对象,则返回 true。否则,返回false

那么“同一个对象”是什么意思呢?这意味着他们不仅看起来像彼此,而且在记忆中也处于同一位置。这意味着 ObjectObject 之间的唯一时间是 ===

var a = {},
    b = {}, // identical to `a`
    c = a;  // same as `a`
a === b; // false
a === c; // true
b === c; // false

【讨论】:

  • 抽象算法做同样的事情(即对于两个对象引用,===== 是相同的)。
【解决方案2】:

当一个变量的值是一个对象时,嗯,它不是一个对象:它是一个对象的引用。包含对 same 对象的引用的两个变量确实相等:

var myObj = { hello: "world" };
var a = myObj;
var b = myObj;

if (a == b) alert("YES!!"); // YES!!

==运算符两边都有对象引用时,进行比较是为了测试对象是否引用同一个对象。当涉及原始值时,语义不同:直接比较值。

【讨论】:

  • 你知道大多数JS引擎中是否使用flyweight方法来表示字符和数字?
  • @plalx 这取决于每个 VM 的实施者。短字符串常量、0 和 1 等数字更可能出现这种情况。
  • @Pointy 你能解释一下“它是对对象的引用”是什么意思吗?我想我根本不完全理解pass by valuepass by reference
  • @Growler 这与参数传递无关,尽管我认为它是相关的。当您分配“对象值”时,您分配的不是对象的副本,而是对对象本身的引用。对于原语,情况并非如此(尽管很难说,因为原语无论如何都是不可变的;换句话说,值“5”不能变成“6”)。
【解决方案3】:

通常,=== 运算符检查类型,如果它们相同,则检查值。对象类型包含一个引用,因此,为了相等,它们必须引用同一个对象并且属于同一类型。字符串文字值不是引用,它是一个值,因此 === 将为字符串文字生成 true,但不会为 "abc" === new String("abc") 因为后者是一个对象。

更多信息可以在这里找到:很多细节可以从这里探索:Which equals operator (== vs ===) should be used in JavaScript comparisons?

【讨论】:

    【解决方案4】:

    首先,JavaScript 对象不是 DOM 的一部分。 DOM(文档对象模型)是构成页面的 HTML 元素。他们一起合作,但没有直接联系。

    基本上,是的,原语是一种特殊情况。您可以将其视为原语的值是一个常数(在某种意义上)。

    以数字 5 为例。无论我声明 5 多少次,5 总是等于 5。因此,说 {var a holding the value 5} 等价并不夸张到 {var b 持有值 5}。这个概念对于字符串来说有点模糊,但它仍然成立。 “abc”字符串始终与任何其他包含“abc”字符串的变量相同。

    这也不适用于对象。

    如果你有两个变量持有同一个对象,它们是等价的。

    var a = {};
    var b = a;
    console.log(a == b); // true
    console.log(a === b); // true
    

    但是,如果我们创建两个看起来相似的对象:

    var a = {};
    var b = {};
    console.log(a == b); // false
    console.log(a === b); // false
    

    一开始这似乎有点奇怪,但请想想正在发生的内部运作。考虑当您将对象传递给函数时,如果您更改该对象,它会在函数之外更改为。它是通过引用传递的。

    这意味着您可以想象一个指针(内存地址)存储在变量中。所以,如果你想象它们里面有内存地址(比如 0x123456 和 0x654321),那么它就更有意义了(0x123456 和 0x654321 是不同的,所以你不会花费它们相等)。它们是两个独立的东西,在内存中占据各自的区域。

    有意义吗?

    【讨论】:

      【解决方案5】:

      您可以从多个层面回答这个问题。

      字符串

      事实上,就严格比较运算符而言,字符串的处理方式与对象不同。

      从语义上讲,这比使用strcmp 或等效机制来比较两个字符串更方便。

      在实现方面,成本可以忽略不计,因此 JavaScript 可以为您提供这种便利。

      顺便说一句,告诉严格相等运算符的人检查两个变量是否指向同一个内存位置是错误。对于字符串,如果字符串内容相等,则 === 将成功,无论它们位于内存中的何处。

      对象

      在语义上,与数字或字符串等基本类型相反,很难为对象提供一组一致的比较运算符。
      您可以对相等性进行深入比较,但更大/更低的运算符意义不大。

      这里选择的Javascript比较不一致。

      • 相等比较的语义(=====)仅限于引用
        (即,如果引用相等,===== 将成功)。

      在实施方面,深入比较可能会非常昂贵。
      还有一些细节是如何解释未定义的属性。

      无论如何,JavaScript 并没有选择实现深度比较,所以如果你想要一个,你必须自己做。
      并且已经编写了数 TB 的代码来尝试提供理想的深入对象比较功能。

      • 有序比较的处理方式完全不同。

      您可以定义一个valueOf 方法,该方法将返回您希望用于有序比较的任何原始值,例如

      myObject.prototype.valueOf = function(){return this.my_comparison_value; };
      

      如果没有明确定义,valueOf 将默认为 "[object Object]"

      所以如果你不提供valueOf 方法:

      • <> 运算符将始终返回 false (这是有道理的)。
      • >=<=总是返回 true,无论引用是否相等
        (这不太有意义)。

      现在,如果您煞费苦心地定义 valueOf,则相等比较仍然不会使用它。
      获得一致行为的唯一方法是将<=>= 结合起来,例如

      if (a >= b && a <= b) { // equality using valueOf
      

      对于浏览器提供的原始对象(如 DOM 元素),排序运算符的行为取决于浏览器决定返回的默认值。
      除非您真的知道自己在做什么,否则我不建议您使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-30
        • 2017-07-16
        • 1970-01-01
        • 1970-01-01
        • 2020-04-24
        • 2013-03-30
        • 1970-01-01
        相关资源
        最近更新 更多