9

There seems to be a mismatch between the common understanding of == and what it actually does. To give some background for the issue:

typeof new Number(1); // returns object
typeof new String(1); // returns object
typeof 1;             // returns number

Seemingly, both Number and String are of object type. No surprise there. However things get interesting for == which should return true when operands are equal regardless of their type.

According to a somewhat authorative description:

Operators attempt to convert the object to a primitive value, a String or Number value, using the valueOf and toString methods of the objects. If this attempt to convert the object fails, a runtime error is generated.

In short, == should compare objects by their primitive value. Surprisingly:

var numa = new Number(1);
var numb = new Number(1);
var stri = new String(1);

numa.toString() == stri.toString(); // returns true, as expected
numa.valueOf() == stri.valueOf();   // returns true, as expected

numa == stri; // returns false (?!)
numa == numb; // returns false (?!!!)

numa == numa; // returns true, as expected

var numx = 1;

numa == numx; // returns true (?)
numb == numx; // returns true (?)
stri == numx; // returns true (?)

It appears when both operands are objects, the == operator uses neither toString() nor valueOf() but something else.

What is the standard definition of object equality for ==?

Saul
  • 17,973
  • 8
  • 64
  • 88
  • 1
    Why the upvotes? The answer is "read the spec". – Tim Down Aug 29 '11 at 11:41
  • @Tim Down: Most technical questions boil down to "reading the spec", without saying. No need to be grudgy. I mean, isn't the whole point of SO to get expert answers - in return for fun and profit? – Saul Aug 29 '11 at 12:14
  • At the point at which you're asking what the "standard definition" is, there's really nowhere else to go. Any answer that doesn't refer to the spec is going to be imprecise or use non-standard terminology. I suppose there could be some value in an answer that paraphrased the spec in terms that some find easier to understand. – Tim Down Aug 29 '11 at 13:16

2 Answers2

5

I believe what you're seeing there, and what's left out of the "somewhat authoritative description", is that == attempts to convert an object to a primitive if, and only if, its comparand is a primitive. If both operands are objects, they're compared as objects, and the equality test is true only if they are the same object (i.e. same instance -- different objects with the same attributes are different, as you see in your numa == numb case).

chaos
  • 122,029
  • 33
  • 303
  • 309
  • I was assuming roughly the same. However I do not understand **exactly what** JavaScript is comparing there. Which identifier is it using? Is that identifier somehow accessible from "outside", e.g. via `console.log`? – Saul Aug 29 '11 at 11:22
  • @Saul: What I would expect that it's comparing is a memory address where the object is allocated or an ID internal to the JS engine. I'm not aware of any JS console that makes it available; it's typically treated as "you don't need to know" information. – chaos Aug 29 '11 at 11:24
3

In short, when operands are objects then == compares references.

From official specification, page 80:

11.9.3 The Abstract Equality Comparison Algorithm

  • If Type(x) is the same as Type(y), then

    a - e omitted, because not applying to objects

    f. Return true if x and y refer to the same object. Otherwise, return false.

chaos
  • 122,029
  • 33
  • 303
  • 309
Yoshi
  • 54,081
  • 14
  • 89
  • 103
  • `==` is **not** strict equality. The question demonstrates that when both operands are objects JavaScript uses **neither** `valueOf()` **nor** `toString()`. – Saul Aug 29 '11 at 11:29
  • Strict equality means **value equality with type equality**. `new Number(1).valueOf() === new Number(1).valueOf()` returns `true` which means operands have **equal values**. `new Number(1) instanceof Number;` also returns `true` which means operands have **equal types**, by definition. However `==` still fails. Hence the question about **standard definition** of object equality. – Saul Aug 29 '11 at 11:51
  • Have a look at at the update. That's your `standard definition`. From that you can see, that objects are not converted if **both** operands are objects. – Yoshi Aug 29 '11 at 12:55
  • @Saul: So I told you the same thing, first, with more feedback, and this answer gets the accept because it cited a spec. How irritatingly Wikipediaesque. – chaos Aug 29 '11 at 15:20
  • @chaos - Sorry about that. I was somewhat torn between Your answer, which is the most outspoken one here, and Yoshi's, which highlights the specified behavior. And you're right, I decided to accept Yoshi's because of a solid citation. – Saul Aug 29 '11 at 15:42