String
, called as a function, converts its argument to a string
. String
, called as a constructor, creates an object whose prototype is the String
function. (Check James's Answer for the relevant ECMAScript specification section.)
This is indeed confusing.
The two equality operators actually do very different things. From the ECMA-262, v 5.1 document, ===
does:
- If
Type(x)
is different from Type(y)
, return false
.
- If
Type(x)
is Undefined
, return true
.
- If
Type(x)
is Null
, return true
.
- If
Type(x)
is Number
, then
a. If x
is NaN
, return false
.
b. If y
is NaN
, return false
.
c. If x
is the same Number
value as y
, return true
.
d. If x
is +0
and y
is -0
, return true
.
e. If x
is -0
and y
is +0
, return true
.
f. Return false
.
- If
Type(x)
is String
, then return true
if x
and y
are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false
.
- If
Type(x)
is Boolean
, return true
if x
and y
are both true
or both false
; otherwise, return false
.
- Return
true
if x
and y
refer to the same object. Otherwise, return false
.
Whereas ==
does:
- If
Type(x)
is the same as Type(y)
, then
a. If Type(x)
is Undefined
, return true
.
b. If Type(x)
is Null
, return true
.
c. If Type(x)
is Number
, then
i. If x
is NaN
, return false
.
ii. If y
is NaN
, return false
.
iii. If x
is the same Number
value as y
, return true
.
iv. If x
is +0
and y
is -0
, return true
.
v. If x
is -0
and y
is +0
, return true
.
vi. Return false
.
d. If Type(x)
is String
, then return true
if x
and y
are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false
.
e. If Type(x)
is Boolean
, return true
if x
and y
are both true
or both false
. Otherwise, return false
.
f. Return true
if x
and y
refer to the same object. Otherwise, return false
.
- If
x
is null and y
is undefined, return true
.
- If
x
is undefined and y
is null, return true
.
- If
Type(x)
is Number
and Type(y)
is String
, return the result of the comparison
x == ToNumber(y)
.
- If
Type(x)
is String
and Type(y)
is Number
, return the result of the comparison
ToNumber(x) == y
.
- If
Type(x)
is Boolean
, return the result of the comparison ToNumber(x) == y
.
- If
Type(y)
is Boolean
, return the result of the comparison x == ToNumber(y)
.
- If
Type(x)
is either String
or Number
and Type(y)
is Object
, return the result of the comparison x == ToPrimitive(y)
.
- If
Type(x)
is Object
and Type(y)
is either String
or Number
, return the result of the comparison ToPrimitive(x) == y
.
- Return
false
.
Note that in the spec, the Type
of a primitive string object is String
, whereas the type of any object (including the String
object) is Object
.
With ===
the relevant line is #1
: the Type
of the objects are different, so false
is returned.
With ==
the relevant line is #8
: x
is a String
("Hello world!"
) and y
is an Object
(The String
object containing the string "Hello world!"
). Thus the comparison x == ToPrimitive(y)
is made. ToPrimitive
ends up calling the valueOf
method of the object, or if that method doesn't exist, the toString
method. In this case, a String
object's valueOf
method returns the primitive string
the object contains. Thus the equality operation is done again, this time between two primitive string
s which contain the same text, which returns true
thanks to #1.d
.
JavaScript is a bit messy under the hood...
EDIT: Notice that if two objects are compared, no conversions apply, but rather, rule #1.f
applies. Thus, thanks to the spec, I was able to correctly predict the output of the following code:
> new String("hi") == new String("hi")
false
EDIT: Just thought I'd add that these distinctions are even further blurred by more implicit type conversion. For example, the following works:
> ("hi").toString()
"hi"
but that's not because "hi"
is an object (like in Python):
> typeof "hi"
"string"
But rather, because the .
operator does a conversion from the primitive string
type to the string Object
type (creating a new string object) whose toString
method is then called.