8

Why do the following two lines return different results?

("test" instanceof String) // returns false
("test".constructor == String) // returns true

Tested in the console of chrome version 28.0.1500.95 m

Does it work slightly differently for native types?

Ally
  • 4,894
  • 8
  • 37
  • 45
  • i don't think it's a duplicate. it's actually a more general question. – basilikum Aug 05 '13 at 10:39
  • @basilikum I agree. In addition I think the answers to the possibly duplicate question itself are insufficiently descriptive. I vote to reopen this question. – Aadit M Shah Aug 05 '13 at 10:57
  • For what it's worth read the following answer: http://stackoverflow.com/a/18057157/783743 – Aadit M Shah Aug 05 '13 at 11:35
  • Your answer is interesting thanks, `native types have a constructor wrapper` is the explanation to the above. It's also useful to know that you can initialize those wrapper types with the first parameter as the primitive value. – Ally Aug 05 '13 at 11:41
  • 2
    @Ally i think the explanation is when you write `"test"` it actually does `String("test");` and you get a primitive (so instanceof won't work because it's not an object). But when you try to use a literal as an object, the browsers convert it to a `String` object, that's why `.constructor` property appears. – meze Aug 05 '13 at 13:04
  • Thanks for the explanation that makes it much easier to understand what's going on. – Ally Aug 05 '13 at 13:16
  • @meze is right. Autoboxing is the reason. – georg Aug 05 '13 at 14:49
  • related, if not duplicate: [JavaScript inheritance and the constructor property](http://stackoverflow.com/q/8093057/1048572) – Bergi Feb 21 '16 at 15:50

2 Answers2

5

constructor is just a property of the internal [[prototype]] property, that can easily be manipulated:

function A(){}
function B(){}
A.prototype.constructor = B;

var a = new A();

console.log(a.constructor); //B

The instanceof operator however checks the internal prototype chain and is not so easily to be fooled, even if you change the complete prototype property of the constructor function:

function A(){}
function B(){}
A.prototype = B.prototype;

var a = new A();

console.log(a instanceof A); //true
console.log(a instanceof B); //false

So, why is "test" instanceof String === false but ("test".constructor == String) === true?

First of all, "test" is a primitive and primitives are never an instance of anything. What actually happens when you use instanceof is that the internal [[HasInstance]] method of the constructor is called with the possible instance as an argument. So a instanceof A translates roughly to:

`A.[[HasInstance]](a)`

The ECMA Specs have this to say to [[HasInstance]]: http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.3

[[HasInstance]] (V)

Assume F is a Function object.

When the [[HasInstance]] internal method of F is called with value V, the following steps are taken:

  1. If V is not an object, return false.
  2. ....

In other words: If the left hand side of instanceof is not an object, the operator will return false.

("test".constructor == String) === true works for a different reason: If you try to access a property of a primitive, the primitive will be temporarily converted into an object. So "test".constructor is roughly equal to:

(new String("test")).constructor

in which case you are actually creating an object, with a constructor function and requesting the constructor property afterward. So it is no surprise, that it will return String.

basilikum
  • 10,378
  • 5
  • 45
  • 58
1

The main difference is that instanceof inspects the object's prototype chain whereas checking the constructor only checks to see if it was created from the same constructor.

Example:

function MyObject() {
    this.sayHi = function() { alert('Hi!'); }   
}

var x = new MyObject();
alert(x.constructor === Object);
alert(x instanceof Object);
Mike Thomsen
  • 36,828
  • 10
  • 60
  • 83