【问题标题】:Is there a difference between array and number datatype in Javascript prototypal inheritance?Javascript原型继承中的数组和数字数据类型有区别吗?
【发布时间】:2025-12-27 16:50:07
【问题描述】:

我是 javascript 原型继承的书呆子。我可以理解下面代码中发生的事情

function Hamster() {  }
Hamster.prototype = {
  food: [],
  found: function(something) {
    this.food.push(something)
  }
}

// Create two speedy and lazy hamsters, then feed the first one
speedy = new Hamster()
lazy = new Hamster()

speedy.found("apple")
speedy.found("orange")

alert(speedy.food.length) // 2

下面的行也是警报2 b'coz 两个对象都在共享来自Hamster 原型的food 数组

alert(lazy.food.length) // 2

但如果我将数组的数据类型更改为数字,food 键不会在两个实例之间共享

function Hamster() {  }
Hamster.prototype = {
  food: 0,
  found: function(something) {
    this.food = something
  }
}

// Create two speedy and lazy hamsters, then feed the first one
speedy = new Hamster()
lazy = new Hamster()

speedy.found(123)


alert(speedy.food) // 123

但是下面的行提醒0,你能告诉我为什么这不提醒123

alert(lazy.food) // 0

【问题讨论】:

    标签: javascript arrays oop prototype prototypal-inheritance


    【解决方案1】:

    Hamster 的每个实例都有自己的 food 属性。但是在第一个版本中,它们都指向同一个数组,您正在使用push 对其进行修改。在第二个版本中,它们指向整数,不能原地修改; found 函数重新分配该实例的属性,这对其他实例没有影响。

    要为每个实例赋予其自己的food 数组属性,您需要使用为其分配的构造函数。

    您可以通过以下方式看到类似的行为,它只使用普通变量而不是对象和继承。

    arr1 = [];
    arr2 = arr1;
    arr1.push(1);
    console.log(arr2); // prints [1]
    
    int1 = 0;
    int2 = int1;
    int1 = 1;
    console.log(int2); // prints 0
    

    分配运算符'='从变量中删除指针

    arr1 = [];
    arr2 = arr1;
    arr2 = ['Appple'];
    console.log(arr1); // prints []
    

    【讨论】:

    • 我刚刚修改了found 函数found: function(something) { this.food += something } 而不是重新分配它,但我仍然为lazy 的实例获得0
    • 这没什么区别,this.food += 只是this.food = this.food + 的简写。数字不能原地修改,它们不是数组和对象等复合对象。
    • 要理解的是,在第一种情况下,两个对象对于food仍然有自己的值;只是它们在每种情况下的值都是对内存中同一个对象的引用。
    • 对,@Vimalraj.S 因为在第一种情况第二种情况下,每个对象都有自己的food
    • array.push 创建一个新的引用。这就是重点。两个对象都有一个 food 属性,它引用内存中的 same 数组,因此当您将元素推送到该数组时(通过 either 引用),您仍然总是更新同一个数组。
    【解决方案2】:

    要理解的是,在第一种情况下,两个对象对于food 仍然有自己的值;只是它们的值在每种情况下都是对内存中同一个对象的引用,因此将一个项目推入该属性引用的数组会改变同一个数组。

    @Barmar 的回答,我赞成,已经说了这么多,但这里有另一个例子可以帮助证明这一点:

    function Hamster() {}
    
    Hamster.prototype = {
        food: [],
        found: function(something) {
            this.food = something;
        }
    }
    
    // Create two speedy and lazy hamsters, then feed the first one
    speedy = new Hamster()
    lazy = new Hamster()
    
    speedy.found(["apple"])
    speedy.found(["orange"])
    
    alert(speedy.food) // orange
    alert(lazy.food) // <empty>
    

    在这种情况下,每个food 属性都会获得一个对不同数组的引用,因此很明显每个属性都是独立的。

    要带走的关键:

    保存对象的变量的值是对该对象的引用保存原语(如数字)的变量的值是原语的值

    【讨论】:

    • @Vimal raj.S 您建议的编辑完全取消了我的示例的要点,即表明每个新对象在每种情况下都有自己的 food 属性。我不知道还有什么可以解释的,这样你就明白了。这可能只需要一些时间(或者其他人可能会以不同于我和@Barmar 的方式回答,这对你来说很有意义)。祝你好运!
    • +1,因为您努力尝试解释这一点。
    • @lwburk,不,在您的示例中,speedy.found(["apple"]) 在这里没有任何意义,因为我们在 found 函数中分配值,因此它与使用实例的 speedy.found("apple") 相同food 变量。但是您的回答给出了一个更好的主意,现在我的疑问是 Array.Push 如何在分配运算符 = 时使用参考?
    • 我认为您已经错过了我的示例的全部要点。很抱歉,它没有帮助。
    【解决方案3】:

    在 JavaScript 中,属性查找遵循原型链,而不是属性分配。

    所以,当你说

    this.food = something;
    

    food 属性在对象上创建。因此,它会覆盖 prototype 中的 food。但是当你访问lazy时,由于它是属性查找,首先搜索当前对象,然后是原型,它被定义并赋值为0。这就是为什么它会提示0。

    【讨论】:

    • 但是第二版没有共享,这是他的问题。