javascript

时间:2016-02-03 12:45:15

标签: javascript oop inheritance

这可能是一个古老的问题,但我仍然无法理解它背后的理论。

我们有

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();

没有人触摸b对象数组,为什么javascript引擎从Class原型中获取它为什么不将它只取空数组属于该对象。

修改

所有答案都是正确的,让我们将属性类型更改为原始

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();

因此,结论是附加到顶部原型的所有引用类型都共享给所有实例,而原始数据类型(如数字)则不是。

4 个答案:

答案 0 :(得分:2)

  

没有人触摸b对象数组,为什么javascript引擎从Class原型中获取它为什么不采取空数组属于该对象

这就是原型在javascript中运行的方式。我们有object,我们有prototype。 这里的一个重要事实是,当您创建新对象时,它不会复制原型的所有属性和方法。 它实际上具有对prototype对象的引用,并且属性/方法分辨率是动态执行的。

例如,如果您要求对象返回myArray属性,则javascript会执行此操作:

  • objectmyArray吗?不(因为你没有声明this.myArray)
  • object.prototypemyArray吗?是
  • 返回object.prototype.myArray

现在,如果您创建两个Test个对象,它们实际上具有相同的原型并引用相同的prototype.myArray属性:

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

由于ab都具有相同的prototype,因此它们也引用相同的myArray。 这样,通过ab对此数组进行修改会更改两个对象。

更新:如果prototype具有原始值,则ab之间仍会共享:

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

但是当您执行a.primitive++或更明确地a.primitive = a.primitive + 1之类的操作时,您实际上会在primitive对象中创建a属性,但它不会引用prototype了:

// 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

答案 1 :(得分:1)

  

为什么javascript引擎从Class原型中获取它为什么不将空数组属于该对象。

这就是典型的继承是如何运作的。由于您只为原型对象的属性分配了一个数组,而不是每个实例都有一个数组(就像在构造函数中创建赋值一样),只有不属于该对象的空数组并且属性查找转到原型。

答案 2 :(得分:0)

因为当您Test执行测试时,您正在添加Test.prototype.myArray。请将其保留在this.myArray

替换你的代码
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();

答案 3 :(得分:0)

JavaScript中的

原型用作后备。 这意味着如果有问题的对象没有所请求的成员(方法或属性),则查询当前对象的原型以查找该成员。 如果不存在则会查询上层原型并且此过程一直持续到达 Object 原型,这是JavaScript中的基本原型。

以下是一个例子:

ICommand

到达对象原型时,如果仍未找到请求的成员,则会引发错误。

以下是jsfiddle example

希望这一点。