99

I was going to start using === (triple equals, strict comparison) all the time when comparing string values, but now I find that

"foo" === new String("foo")

is false, and same with this:

var f = "foo", g = new String("foo");
f === g; // false

Of course:

f == g; // true

So is it recommended to always use == for string comparison, or always convert variables to strings before comparing?

Michael Butler
  • 5,468
  • 1
  • 35
  • 44
  • 6
    Maybe because `foo` is the pure string and `new String("foo")` is the Object String – Danilo Valente Jun 08 '12 at 15:40
  • Background: http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript – Pekka Jun 08 '12 at 15:40
  • 6
    It is recommended not to create strings with `new String` (Completely pointless) rather than using `==` – Esailija Jun 08 '12 at 15:41
  • 2
    Why would anybody want to use construct like `new String("foo")` in Javascript in the first place? I've never seen such code in code i.e. jQuery... – Robert Koritnik Jun 08 '12 at 15:42
  • ok so if I'm developing a JS library to be used elsewhere, I can assume and require that a function take a parameter as a primitive string, and if the API user passes a String() object I can assume that's incorrect use of the API – Michael Butler Jun 08 '12 at 15:57
  • @MichaelButler: Absolutely, if that's how the API is documented. Require very specific argument types, and you can avoid a bunch of duck typing. –  Jun 08 '12 at 15:58
  • @MichaelButler: Yes. There are very few reasons to explicitly create and use boxed primitives. – SLaks Jun 08 '12 at 16:07
  • I suppose you could use a boxed String object to pass by reference to a function that modifies it. bad practice, but possible. – Michael Butler Jun 08 '12 at 16:13
  • @MichaelButler That would be pointless as strings are immutable in JavaScript anyway. – Peter C Jun 08 '12 at 16:32
  • Actually, that wouldn't even be possible. You can't really modify a boxed `String` object. – SLaks Jun 08 '12 at 16:41
  • 2
    You can use `String(obj)` to convert a boxed string to the primitive once you've received your "string" parameter. `("foo" === String(new String("foo"))) === true` – OrangeDog Jun 08 '12 at 17:02
  • @SLaks, @alpha123: `var s = new String("foo"); s.myprop = 5; alert(s.myprop); // shows 5 alert(s + "bar"); // shows "foobar"`. So I think you **can** modify a boxed String object. Unboxed strings are immutable. Is that what you meant? – Michael Butler Oct 02 '12 at 19:02
  • @MichaelButler: You can add a property to it, but you can't change the value of the string. – SLaks Oct 03 '12 at 00:42
  • See also [What is the difference between string literals and String objects in JavaScript?](http://stackoverflow.com/q/17256182/1048572) – Bergi Jan 04 '17 at 10:32

5 Answers5

126

"foo" is a string primitive. (this concept does not exist in C# or Java)

new String("foo") is boxed string object.

The === operator behaves differently on primitives and objects.
When comparing primitives (of the same type), === will return true if they both have the same value.

When comparing objects, === will return true only if they refer to the same object (comparing by reference). Thus, new String("a") !== new String("a").

In your case, === returns false because the operands are of different types (one is a primitive and the other is an object).


Primitives are not objects at all.
The typeof operator will not return "object" for primitives.

When you try to access a property of a primitive (using it as an object), the Javascript language will box it to an object, creating a new object every time. This is described in the specification.

This is why you cannot put properties on primitives:

var x = "a";
x.property = 2;
alert(x.property) //undefined

Each time you write x.property, a different boxed String object is created.

SLaks
  • 800,742
  • 167
  • 1,811
  • 1,896
34

Using ===,

  • an Object is never equal to anything except another reference to itself.

  • a primitive is equal when compared to another primitive if their type and value are the same.

10

The new word is a criminal here (as usual, may I say)...

When you use new, you explicitly express your desire to work with object. It might be surprising for you, but this:

var x = new String('foo');
var y = new String('foo');
x === y; 

... will give you a mighty false. It's simple: compared are not the objects' insides, but the objects' references. And they, of course, are not equal, as two different objects were created.

What you probably want to use is conversion:

var x = String('foo');
var y = String('foo');
x === y;

... and that will give you, as expected, true as result, so you can rejoice and prosper with your equal foos forever. )

raina77ow
  • 91,589
  • 12
  • 180
  • 210
  • 2
    quick question about using this. You're calling String (a constructor?) without the 'new' keyword. Doesn't this mean you will pollute the scope with any properties assigned within the String constructor? Or does that not happen because the constructor is native code? In other words, suppose the String function contained "this.a = 1;" -- that means your function/object would now have a property a = 1. – Michael Butler Jun 08 '12 at 21:03
  • 1
    I suppose (but cannot say for sure) each of the 'boxing constructor' functions first checks its context - and if it's not a 'newish one' (i.e., a prototype object), switches to the conversion method right away. In case of String that would be `toString()` method, for example. – raina77ow Jun 08 '12 at 23:26
4

foo is the pure string and new String("foo") is the Object String

Danilo Valente
  • 10,599
  • 8
  • 49
  • 65
2

From the node.js REPL ("node" on the command-line if installed):

> "foo" === (new String("foo")).valueOf()
true
> "foo" === new String("foo")
false
> typeof("foo")
'string'
> typeof(new String("foo"))
'object'
> typeof((new String("foo")).valueOf())
'string'
mda
  • 1,048
  • 13
  • 18