10

I'm extending Object like this:

Object.prototype.is_a = function (x) {
  return this instanceof x;
}

All works as expected

"foo".is_a(String) // true
"foo".is_a(Object) // true
"foo".is_a(Array) // false
"foo".is_a(Function) // false
"foo".is_a(Boolean) // false
"foo".is_a(Date) // false
"foo".is_a(Number) // false
"foo".is_a(RegExp) // false

but, when

"foo" instanceof String // false

this keyword on the is_a() function is same as foo right? Why does it return different results?

Adi Inbar
  • 12,097
  • 13
  • 56
  • 69
pyk
  • 203
  • 1
  • 7
  • 1
    @WiktorZychla I have a bias, so I could be wrong. But, I'm not sure this is a duplicate. There's overlap, but this is also about [boxing](http://en.wikipedia.org/wiki/Object_type_(object-oriented_programming)#Boxing) rather than just `instanceof` with primitives. – Jonathan Lonowski Mar 03 '14 at 21:18

4 Answers4

11

First of all, you cannot apply instanceof to primitive values, that's why

"foo" instanceof String

returns false. Primitives are not objects and hence cannot be an instance of a constructor function. *

So why does it seem to work inside the is_a method?

In non-strict mode, the value of this inside a function is always going to be an object (step 3). If this value is not an object, it is implicitly converted to one. You can test this with console.log(typeof this).
That means that the string primitive "foo" is converted to an String object new String("foo") and that's why you can use instanceof on it.

In strict mode, the value of this doesn't have to be an object and is not automatically converted (step 1). Your method would fail in that case:

> Object.prototype.is_a = function (x) {
   'use strict';
   return this instanceof x;
 }
> "foo".is_a(String)
false

*: That's a very simplified explanation. In reality, the instanceof operator delegates the evaluation to the constructor function's internal [[HasInstance]] method, which is defined to return false if the passed value is not an object.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
1

String literals aren't the same as String objects (MDN). It appears that the string literal (which is a string primitive) is automatically boxed into an object when it's used as the binding context of a function (i.e. when it's this inside a function):

>>> typeof "foo"
"string"
>>> Object.prototype.type_of = function (x) {
  return typeof this;
}
function (x) {
  return typeof this;
}
>>> "foo".type_of()
"object"

That explains your instanceof behavior, as well. This behaves as you might expect:

>>> new String("foo") instanceof String
true
>>> new String("foo") instanceof Object
true
>>> new String("foo").is_a(String)
true
>>> new String("foo").is_a(Object)
true
>>> new String("foo").is_a(Array)
false
kevingessner
  • 18,559
  • 5
  • 43
  • 63
1

JavaScript has both primitive and object versions of strings, numbers and booleans. String literals define primitives rather than objects. If you did typeof "foo", you would get "string" rather than "object". But when you access a property of the string, it creates a temporary String object from the primitive string and then accesses the corresponding property of that object, so it this instanceof String is true inside that temporary String object's method.

In order to test whether something is a string while accounting for both primitives and objects, you need to test typeof foo === "string" || foo instanceof String.

Chuck
  • 234,037
  • 30
  • 302
  • 389
0

instanceof needs an object defined, this example returns true:

var f = new String("foo");
alert( f instanceof String);

This is more similar to your example:

alert( new String("foo") instanceof String);
T McKeown
  • 12,971
  • 1
  • 25
  • 32