You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何将数组作为原型赋值与简单对象表现不同?

为什么原型上的数组会被实例共享,而简单属性不会?

你遇到的核心问题是值类型和引用类型在原型链中的行为差异,以及赋值操作对实例属性的影响。先看两段代码的对比:

正常表现的简单属性代码

const Amount = {
  _amount: 0,
  set_Amount: function (foo) {
    this._amount = foo;
  },
  get_Amount: function () {
    return this._amount;
  },
};

function func_a() {}
function func_b() {}

const obj_a = new func_a()
const obj_b = new func_b()

Object.assign(func_a.prototype, Amount);
Object.assign(func_b.prototype, Amount);

obj_a.set_Amount(1)
obj_b.set_Amount(2)

console.log(obj_a.get_Amount()) //1
console.log(obj_b.get_Amount()) //2

出现共享问题的数组代码

const objList = {
  _list: [],
  add_item: function (foo) {
    this._list.push(foo)
  },
  list: function () {
    return this._list;
  },
  total: function (){ 
    let x = 0;
    for (let item in this._list) {
      x = Number(x) + Number(this._list[item]);
    }
    return x;
    }
}

function type_a() {}
function type_b() {}

const obj_a = new type_a()
const obj_b = new type_b()

Object.assign(type_a.prototype, objList);
Object.assign(type_b.prototype, objList);

obj_a.add_item(1)
obj_a.add_item(2)
obj_b.add_item(3)
obj_b.add_item(4)

console.log(obj_a.list()) //  [1, 2, 3, 4]
console.log(obj_a.total()) // 10
console.log(obj_b.list()) //  [1, 2, 3, 4]
console.log(obj_b.total()) // 10

原因解释

  1. 简单属性的情况:
    调用obj_a.set_Amount(1)时,this._amount = foo是直接给obj_a实例自身添加了一个_amount属性。JavaScript属性查找规则是先找实例自身,再找原型,所以后续get_Amount取的是实例自己的属性,和原型上的_amount无关。每个实例都有独立的_amount,自然互不影响。

  2. 数组(引用类型)的情况:
    调用obj_a.add_item(1)时,this._list.push(foo)并没有给obj_a实例添加新的_list属性,而是顺着原型链找到了原型上的数组。数组是引用类型,所有实例指向的都是同一个数组对象的引用,不管哪个实例调用push,都是在修改同一个数组,最终所有实例看到的结果一致。

解决方案

要让每个实例拥有独立的数组,必须在构造函数里给实例初始化自己的_list,而非把数组放在原型上:

function type_a() {
  // 每个实例创建时生成新的数组
  this._list = [];
}
function type_b() {
  this._list = [];
}

// 原型只放方法,复用逻辑
const objListMethods = {
  add_item: function (foo) {
    this._list.push(foo)
  },
  list: function () {
    return this._list;
  },
  total: function (){ 
    let x = 0;
    for (let item of this._list) { // 用for...of遍历数组更合适
      x += Number(item);
    }
    return x;
  }
}

Object.assign(type_a.prototype, objListMethods);
Object.assign(type_b.prototype, objListMethods);

修改后,每个实例都会有自己的_list数组,操作时互不干扰。

补充:原型的设计初衷是复用方法这类无需每个实例单独存储的逻辑,实例的状态属性(尤其是引用类型)应放在实例自身中,避免共享问题。


内容的提问来源于stack exchange,提问作者ctalley5

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 06:18:24