4

if I just use obj.prototype.property = val, everything will be ok, code like

function animal() {}
var frog = new animal();
animal.prototype.color = 'Green';
console.log(frog.color);
// 'Green'

But if I use obj.prototype = {key:val} after new keyword, it will give me a undefined, code like

function animal() {}
var frog = new animal();
animal.prototype = {
    color: 'Green'
};
console.log(frog.color);
// 'undefined' -- why?

And if I change the order which let the prototype before the new keyword, it will be ok, so weird and why? because we know an object’s prototype allows us adding properties to all instances of that object (even to the existing instances), right?

code like

function animal() {}
animal.prototype = {
    color: 'Green'
};
var frog = new animal();
console.log(frog.color);
// 'Green'
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
Roy
  • 731
  • 3
  • 10
  • 24
  • possible duplicate of [JS prototype objects not inherited?](http://stackoverflow.com/questions/23970431/js-prototype-objects-not-inherited) – Qantas 94 Heavy Feb 22 '15 at 06:35
  • The following answer may help you understand the role of prototype and constructor functions. Your question is already answered but putting an instance specific property on the prototype is an indication you may not understand what prototype is: http://stackoverflow.com/a/16063711/1641941 – HMR Feb 23 '15 at 00:31

2 Answers2

1

When you create a new Object with new keyword, the newly created object's internal [[Property]] object will be set to the constructor function's prototype object.

function animal() {}
var frog = new animal();

console.log(Object.getPrototypeOf(frog) === animal.prototype);
# true

animal.prototype = {
    color: 'Green'
};

console.log(Object.getPrototypeOf(frog) === animal.prototype);
# false

console.log(frog.color);

In the first console.log, it prints true because, new has set the animal's prototype object as the frog's internal [[Prototype]] object. But, when you assign some other object to animal's prototype, frog's internal [[Prototype]] object still refers to the old object, which doesn't have color property. That is why it is printing undefined.

When you change the order, when new statement is encountered, it gets the animal's prototype object (which is the new object you assigned), and creates the frog object. That is why it has color property.

Now, you might be wondering why the first case is working fine. Because,

animal.prototype.color = 'Green';

is not replacing animal.prototype with some other object, but it mutates (or augments, if you prefer) the animal.prototype object. So, frog's internal [[Prototype]] property is still the same as the animal.prototype object.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
0

Because you are assigning a brand new object. prototype is not the [[Prototype]] of an object. new uses this property to set up the internal property. So what happens is that the reference to the prototype object that new uses, is not the same as the object you assigned later. You shouldn't override the prototype property, always extend it, like in your first example:

function Animal(){}
var frog = new Animal();
Animal.prototype.color = 'green';
console.log(frog.color); // green
elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • Because if you assign a new `prototype` object first, then `new` will grab that new object. If you do it later, then it is too late, `new` already used the `prototype` property that the function has by default. – elclanrs Feb 22 '15 at 06:11
  • thx Mr. White, you say shouldn't override the prototype? but assigning a {} to prototype is very convenient, if not, I'll make prototype.a, prototype.b again and again – Roy Feb 22 '15 at 06:36
  • Ok, but this is not about convinence, it is about the effects, as you saw. What you can do is `extend(Animal.prototype, {color: 'green'})` and get `extend` from npm, or underscore or something. – elclanrs Feb 22 '15 at 06:44