array type property shared between multiple object

2019-03-05 16:42发布

问题:

it could be old question but i still not able to understand the theory behind it.

we have

function Test(name) {
  this.name = name;
}
Test.prototype.myArray = []; // I know if i move this to constructor it can resolve my problem
Test.prototype.what = function() {
  document.writeln("<br/>" + this.myArray);
}
Test.prototype.add = function() {
  this.myArray.push(this.name);
}

var a = new Test('Scott');
a.add();
a.what();

var b = new Test('Smith');
document.writeln("<br/>"  + b.myArray + " <= Check this one")
b.add()
b.what();

nobody touch b object array, why javascript engine get it from Class prototype why not it just take empty array belong to that object.

EDIT:

All the answers are correct, let change the type of property to primitive

function Test(name) {
  this.name = name;
}
Test.prototype.primitive = 1;
Test.prototype.myArray = []; // I know if i move this to constructor it can resolve my problem
Test.prototype.what = function() {
  document.writeln("<br/>" + this.myArray + " primitive:" +this.primitive);
}
Test.prototype.add = function() {
  this.primitive++;
  this.myArray.push(this.name);
}

var a = new Test('Scott');
a.add();
a.what();

var b = new Test('Smith');
document.writeln("<br/>"  + b.myArray + " primitive:" +b.primitive +" <= Check this one now primtive is not shared")
b.add()
b.what();

So conclusion is all reference types attached to top prototype are shared to all instances and primitive datatypes like number are not.

回答1:

why javascript engine get it from Class prototype why not it just take empty array belong to that object.

That's just how prototypical inheritance works. As you only assigned one array to the prototype object's property, instead of an array to every instance (like it happens if you create an assign in the constructor), there simply is no empty array belonging to the object and the property lookup goes to the prototype.



回答2:

nobody touch b object array, why javascript engine get it from Class prototype why not it just take empty array belong to that object

That's the way prototype works in javascript. We have an object and we have its prototype. An important fact here is that when you create a new object, it doesn't copy all the properties and methods of the prototype. It actually have a reference to the prototype object and the property / method resolution is performed dynamically.

For example, if you ask the object to return a myArray property, javascript does this:

  • Does object have myArray? No (since you didn't declare this.myArray)
  • Does object.prototype has myArray? Yes
  • Return object.prototype.myArray

Now if you create two Test objects, they actually have the same prototype and refer to the same prototype.myArray property:

      ------------------
      | Object a       |
      |                |                 ---------------------
      | name = 'Scott' |                 |                   |
      | prototype  ----|---------------> |   prototype       |
      ------------------                 |                   |
                                         |   myArray = []    |
      ------------------                 |                   |
      | Object b       |                 |                   |
      |                |                 |                   |
      | name = 'Smith' |                 |                   |
      | prototype  ----|---------------> |                   |
      ------------------                 ---------------------

Since both a and b have the same prototype, they also refer to the same myArray. This way the modification of this array via a or b will change it for both objects.

Update: in the case when prototype has a primitive value, it is still shared between a and b:

Test.prototype.primitive = 1
a = new Test();
a.primitive; // 1
b = new Test();
b.primitive; // 1

// Update prototype's primitive
Test.prototype.primitive += 1
// a and b objects refer to the updated value
a.primitive; // 2
b.primitive; // 2

But when you do something like a.primitive++ or, more explicitly, a.primitive = a.primitive + 1, you actually create the primitive property in the a object and it doesn't refer to the prototype anymore:

// Now a.primitive is actually created in the a object and
// does not refer to the prototype anymore
a.primitive++;
a.primitive; // 3
Test.prototype.primitive; // 2
b.prototype.primitive; // 2

// Now prototype primitive updates will only affect object b
Test.prototype.primitive += 2;
a.primitive; // 3
b.prototype.primitive; // 4


回答3:

because you are adding to the Test when you do Test.prototype.myArray not to the instance of test. Just keep it in this.myArray

replace your code with

function Test(name) {
  this.name = name; this.myArray = []; //observe this change
}
Test.prototype.what = function() {
  console.log("<br/>" + this.myArray);
}
Test.prototype.add = function() {
  this.myArray.push(this.name);
}
var a = new Test('Scott');
a.add();
a.what();
var b = new Test('Smith');
console.log("<br/>"  + b.myArray + " <= Check this one")
b.add()
b.what();


回答4:

prototypes in JavaScript are used as fallbacks. Meaning that if the object in question doesn't have the requested member(method or property), the prototype of the current object is queried to find that member. If it is not there the upper prototype is queried and this process is going up until it reaches the Object prototype Which is the base prototype in JavaScript.

Here is an example :

var test1,test2,test3;

Object.prototype.getInfo = function(){
    return this.firstName + " - " + this.lastName;
}

function test1(){
    this.firstName = "ham";
}

test2.prototype = test1;
function test2(){
    this.lastName = "bam";
}

test3.prototype = test2;
function test3(){
    return this.getInfo();
}

test1(); // at this level firstName property is available
test2(); // at this level firstName,lastName  properties are available
test3(); // returns 'ham - bam' because the main prototype Object has the method getInfo and we have firstName,lastName from the previous prototypes.

When reaching the Object prototype, if the requested member still not found, an error is thrown.

Here is the jsfiddle example

Hope this hepls.