8

Possible Duplicate:
Why does (“foo” === new String(“foo”)) evaluate to false in JavaScript?

Over here I caught the advice that it's best to use non type-coercive string comparison, but in Chrome, I discovered something kind of odd:

var t1 = String("Hello world!");
var t2 = new String("Hello world!");
var b1 = (t1==t2); // true
var b2 = (t1===t2); // false

Is this standard behavior? If so, what are the respective types of t1 and t2? Thanks.

1
  • 1
    You can check by using the typeof operator. And read the spec for the full details. Commented Aug 15, 2012 at 21:22

6 Answers 6

9

If you don't use the "new" keyword with String, you get a primitive string.

If you use "new" keyword, you get a string object instead of primitive.

When you use == it will try to convert to a comparable type, so it can be equal.

If you use ===, it won't convert, so an object can not equal a primitive.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 In addition: String is a special type of object in that has [ToPrimitive] is defined over it. There is no other custom object for which == (using the above string values) would be equal.
6

Here is the explanation

typeof String("Hello world!");
"string"

And:

typeof new String("Hello world!");
"object"

when you use === it is paying attention to the type so it returns false

3 Comments

It's not an explanation, but yeah it's showing why they aren't equal. Explnation would be telling why new String and String create different types.
True, but you didn't explain why == is evaluating true while === evaluates to false. The explanation is that == compares values while === compares both value and type. One is a string while the other is an object, and that's why === is false.
This also doesn't explain why == works (there are very few objects for which == makes sense in JavaScript) .. just why === doesn't.
5

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:

  1. If Type(x) is different from Type(y), return false.
  2. If Type(x) is Undefined, return true.
  3. If Type(x) is Null, return true.
  4. 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.
  5. 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.
  6. If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
  7. Return true if x and y refer to the same object. Otherwise, return false.

Whereas == does:

  1. 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.
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
  4. If Type(x) is Number and Type(y) is String, return the result of the comparison
    x == ToNumber(y).
  5. If Type(x) is String and Type(y) is Number, return the result of the comparison
    ToNumber(x) == y.
  6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
  7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
  8. If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
  9. If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
  10. 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 strings 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.

6 Comments

You're missing part of ==='s 6. and 7., also I think a quote block would be more readable than a code one.
thanks, but how would i indent the lines? added in missing bits of 6+7
Good question. +1 for the completion. I'm checking what's the easiest way to indent and keep the numbering.
Eh guess it's readable enough like this, blockquote looks like a wall of text, least like this it's more colored. =] People can always read the formatted version in your link.
I think the indenting and code hinting is correct. Please check.
|
3

This behaviour is detailed in the ECMAScript 5 specification, 15.5.1 and 15.5.2:

When String is called as a function rather than as a constructor, it performs a type conversion.

...

Returns a String value (not a String object) computed by ToString(value). If value is not supplied, the empty String "" is returned.

So String("some string") creates a string value.

When String is called as part of a new expression, it is a constructor: it initialises the newly created object.

So new String("some string") creates an instance of the String object.


And to actually answer your questions:

Is this standard behavior?

Yes, for the reasons detailed above.

If so, what are the respective types of t1 and t2

You can check this with the typeof operator:

console.log(typeof t1); //string
console.log(typeof t2); //object

1 Comment

+1, also new String("Hello world!").toString() === String("Hello world!")
1

This is happening because the == operator only checks if the values are the same, whereas === checks both the value and type. new String("Hello world!") is not actually being given the type string, it is an object, while String("Hello world!") is actually a string.

Comments

0

The first example String("Hello world!)" creates a primitive string while the second example new String("Hello world!") creates an String object.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.