5

The instanceof operator should look at the prototype, no? Why does it not change its answer after the object's prototype has been changed? Example below:

// The .prototype of objects created with 'new MyKlass'
// is MyKlass.prototype
var MyKlass = function(name, age) {
  this.name = name;
  this.age = age;
}

var xx = new MyKlass('xx', 20);
console.log(xx instanceof MyKlass);      // true, OK

xx.prototype = new String('s');
console.log(xx instanceof MyKlass);      // also true, WHY???
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
zpzp
  • 75
  • 3

3 Answers3

9

This case is explained in the MDN :

Note that if the value of an instanceof test can change based on changes to the prototype property of constructors, it cannot be changed by changing an object prototype, because changing an object prototype is not possible in standard ECMAScript. It is however possible using the non-standard __proto__ pseudo-property

This would log false :

xx.constructor.prototype = new String('s');
console.log(xx instanceof MyKlass);

In short, you shouldn't try to mutate JavaScript objects, they weren't designed to be mutable. I don't know what's your use case but there's probably a better solution, be it composition, internal state, or something's else.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • Why can `prototype` of `MyKlass` change but not `xx.prototype`? Arent both `MyKlass` and `xx` objects? – zpzp Jun 27 '13 at 13:06
  • @OliverWatkins Mutating an object is the general operation of changing its class. Most OOP (or POOP) languages don't let you do that because it's messy. – Denys Séguret Jun 27 '13 at 13:08
  • @zpzp I don't get your comment. Property access in JavaScript is often done via getters and setters, even if it's not directly visible. See http://stackoverflow.com/questions/9959727/what-is-the-difference-between-proto-and-prototype-in-javascript – Denys Séguret Jun 27 '13 at 13:10
  • so it _is_ possible on `MyKlass` but not on any random object? – zpzp Jun 27 '13 at 13:15
  • When you set the `prototype` property of an object which isn't a function, you're adding a new property, you're not changing the internal `__proto__`. EDIT : Bergi explains it, see his answer for this point. – Denys Séguret Jun 27 '13 at 13:15
3

It does not look at .prototype but [[prototype]], or what is available in some browsers as .__proto__

xx.__proto__ = new String("s");
console.log(xx instanceof MyKlass); 
//false
console.log(xx instanceof String); 
//true

Assigning a .prototype property to a non function has no effect except the normal assignment of any normal property really. And for functions that only has an effect when the function is used in instanceof check or called with new.

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • does setting `__proto__` have standard ECMAScript parallel (maybe in ES 5) ? – zpzp Jun 27 '13 at 13:10
  • @zpzp no but it seems that it will be available in ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto – Esailija Jun 27 '13 at 13:11
3

The instanceof operator should look at the prototype, no?

Yes, it does. See the MDN docs.

Why does it not change its answer after the object's prototype has been changed?

var xx = new MyKlass('xx', 20);
xx.prototype = new String('s');

Because you didn't change the prototype of your xx object, but gave it a prototype property. Object.getPrototypeOf(xx) === MyKlass.prototype still applies. See __proto__ VS. prototype in JavaScript for details. What would work:

MyKlass.prototype = {}; // overwrite with a different object
console.log(xx instanceof MyKlass); // false now, xx doesn't inherit from the {}

or

xx.__proto__ = String.prototype; // or something
console.log(xx instanceof MyKlass); // false now, xx doesn't inherit from MyKlass.prototype

Notice that writing to the internal [[prototype]] via __proto__ is non-standard in ES5

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • So the `.prototype` property of functions is special in a way, because setting it has meaning beyond just setting the property? – zpzp Jun 27 '13 at 13:20
  • Yes, it refers to the object which instances or set to inherit from when the [function is called as a constructor with `new`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new) – Bergi Jun 27 '13 at 13:22