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

Knockout可观察属性在JS原型继承中出现值覆盖问题如何解决?

问题结论

这不是Knockout的bug,是JavaScript原型链的原生特性导致的问题。

原因分析

  • 普通字符串属性版本运行正常的原因:你在Orange、Apple构造函数中执行this.fruitName = "xxx"时,会直接在当前实例对象上新增自有属性fruitName,覆盖原型链上的同名属性,每个实例的属性完全独立,因此输出符合预期。
  • 替换为Knockout observable后输出异常的原因:你将fruitName定义为Fruit.prototype上的属性,而observable本质是引用类型的函数对象,所有继承自Fruit的实例默认共享原型上的同一个observable。你在子类构造函数中执行this.fruitName("xxx")时,并没有给实例新增自有属性,只是调用了原型上共享的observable的赋值方法,后执行的Apple实例赋值会覆盖之前Orange实例的赋值,最终两个实例调用都返回最后设置的I am an apple。
  • 原有代码额外隐患:调用父类构造函数时写的Fruit.call()没有传入当前实例this,会导致父类构造函数内的this指向错误;另外Apple.prototype.constructor被错误赋值为Orange,属于笔误。

解决方法

不要把observable属性定义在父类原型上,改为在父类构造函数内部初始化,保证每个实例都拥有独立的observable:

function Fruit(){
  // 每个实例单独创建observable,不会共享
  this.fruitName = ko.observable("I am a fruit");
  this.who = function(){ console.dir(this.fruitName()); }
}

function Orange(){
  // 调用父类构造函数时传入当前实例this
  Fruit.call(this);
  this.fruitName("I am an orange");
}
Orange.prototype = new Fruit();
Orange.prototype.constructor = Orange;

function Apple(){
  Fruit.call(this);
  this.fruitName("I am an apple");
}
Apple.prototype = new Fruit();
// 修正constructor指向的笔误
Apple.prototype.constructor = Apple;

var orange = new Orange();
var apple = new Apple();
orange.who(); // 输出 I am an orange
apple.who(); // 输出 I am an apple

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 06:45:04