【问题标题】:array type property shared between multiple objects in javascriptjavascript中多个对象之间共享的数组类型属性
【发布时间】:2016-02-03 12:45:15
【问题描述】:

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

我们有

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 引擎从类原型中获取它,为什么不只取属于该对象的空数组。

编辑:

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

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

所以结论是所有附加到顶级原型的引用类型都共享给所有实例,像数字这样的原始数据类型不是。

【问题讨论】:

  • 这就是 javascript 中属性查找的工作方式。当您编写a.myArray 时,引擎首先检查a 是否有一个名为myArray 的属性。由于它不引擎上升原型链。因此,每当您访问 myArray(使用任何共享相同原型的起始对象)时,您将获得相同的数组,除非您在对象本身上定义 myArray 属性。

标签: javascript oop inheritance


【解决方案1】:

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

这就是原型在 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 之类的操作时,您实际上在a 对象中创建了primitive 属性,它不再引用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

【讨论】:

  • @A.T.我不是 100% 确定并且需要重新检查这一点,但我认为当您更新原始值时,它可以在对象内创建它的实际副本。因此,更新后,您在对象内部拥有自己的 primitive 副本,并且它与 prototype 断开连接。
【解决方案2】:

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

这就是原型继承的工作原理。由于您只为原型对象的属性分配了一个数组,而不是为每个实例分配一个数组(就像您在构造函数中创建分配时发生的那样),所以 没有属于该对象的空数组并且属性查找转到原型。

【讨论】:

  • 在原始数据类型的情况下不是这样,对吧?
  • @A.T.:保存原始值的属性的继承与保存对象的属性的工作方式相同。唯一的区别是原始值可以毫无问题地共享,因为您无需修改​​它们(就像您对问题中的数组所做的那样)。
  • @A.T.:注意this.primitive++ 等价于this.primitive = this.primitive+1,这是一个赋值,它在实例上创建一个自己的属性。如果您执行this.myArray = this.myArray.concat([this.name]);,它将与您的阵列相同
  • 哦,很好,这很混乱......为什么我错过了。谢谢。 :)
【解决方案3】:

因为您在执行 Test.prototype.myArray 时添加到 Test 而不是测试实例。保存在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();

【讨论】:

    【解决方案4】:
    JavaScript 中的

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

    这是一个例子:

    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.
    

    到达Object原型时,如果仍然没有找到请求的成员,则抛出错误。

    这里是jsfiddle example

    希望有帮助。

    【讨论】:

      猜你喜欢
      • 2015-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-22
      相关资源
      最近更新 更多