javascript原型继承-共享属性

Posted

技术标签:

【中文标题】javascript原型继承-共享属性【英文标题】:javascript prototype inheritance - shared property 【发布时间】:2013-03-05 04:43:02 【问题描述】:

我在原型中保存了一个属性_data 作为所有创建对象的定义。

 function A() 
 A.prototype._data = [];

现在从A 创建的所有对象都具有_data 属性。

我想要原型继承,其中原型的_data 将具有来自原型链中所有原型的_data 值。

不知道直接方式,在这个例子中我使用了一个getter get()

 function A() 

 A.prototype._data = [];

 A.prototype.add = function(rec) 
   this.__proto__._data.push(rec);
 

 A.prototype.get = function() 
   if(typeof this.__proto__.constructor.prototype.get == 'function')
   
     return this.__proto__.constructor.prototype.get().concat(this.__proto__._data);
   
   else
   
     return this.__proto__._data || [];
   
 

 function B() 
 B.prototype = Object.create(A.prototype,  constructor:  value: B );
 B.prototype._data = [];

当我创建对象a 的值aa 和对象b 的值bb 时,b.get() 返回[aa, bb]。之后,如果原型A_data 将扩展为aaaa,则函数b.get() 返回[aa, aaaa, bb]

 var a = new A(), b = new B();

 a.add('aa');
 b.add('bb');
 console.log(b.get()); // [aa, bb]

 a.add('aaaa');
 console.log(b.get()); // [aa, aaaa, bb]

 // EDITED - _data in A prototype shoud be without B
 console.log(a.get()); // [aa, aaaa]

这是一个很好的(标准)方法来实现这一点吗?我的意思是在 Object.create 时使用构造函数更正,并在 constructor.prototype 时引用父原型?

这是一个演示:http://jsfiddle.net/j9fKP/

所有这一切的原因是 ORM 库中方案的字段定义,其中允许方案的继承。子方案必须具有父方案的所有字段。

【问题讨论】:

javascript object members that are prototyped as arrays become shared by all class instances的可能重复 【参考方案1】:

我想要原型继承,其中原型的_data 将具有来自原型链中所有原型的_data 值。

那是另一回事。 “原型继承”意味着如果当前对象上有一个_data 属性,它就不会在链中进一步查找。此外,它似乎是一种issue with nested objects,虽然我不确定你真正想要什么。但是,如果您真的想连接它们,让一个数组对象从另一个数组继承几乎没有意义。

所以我认为你的吸气剂真的很好。

这是一个很好的(标准)方法来实现这一点吗?我的意思是在 Object.create 和使用 constructor.prototype 引用父原型时使用构造函数更正

构造函数更正很好,但actually quite useless(特别是如果您期望符合标准的Object.create)。

但是,在 this.__proto__.constructor.prototype 中,.__proto__.constructor.prototype 是多余的。由于两者都是非标准的或 require 构造函数更正,您应该使用标准的Object.getPrototypeOf() function 来获取您的原型对象。

使用以下非常通用的解决方案,您可以任意深度地嵌套继承(A.proto、B-proto、B-instance...)。从A.prototype 继承的所有东西都将有一个add 方法将_data 添加到当前对象,还有一个get 方法遍历原型链并收集所有_data

function A() 
    // this._data = []; // why not?

A.prototype._data = []; // not even explicitly needed
A.prototype.add = function(rec) 
    if (! this.hasOwnProperty("_data")) // add it to _this_ object
        this._data = [];
    this._data.push(rec);

A.prototype.addToAllInstances = function(rec) 
    Object.getPrototypeOf(this).add(rec);

A.prototype.get = function() 
    var proto = Object.getPrototypeOf(this);
    var base = typeof proto.get == 'function' ? proto.get() : [];
    // maybe better:
    // var base = typeof proto.get == 'function' && Array.isArray(base = proto.get()) ? base : [];
    if (this.hasOwnProperty("_data"))
        return base.concat(this._data); // always get a copy
    else
        return base;


function B() 
    A.call(this);

B.prototype = Object.create(A.prototype,  constructor:  value: B );
B.prototype._data = []; // not even explicitly needed

示例用法:

var a = new A();
var b = new B();

a.add('ai');
a.get(); // [ai]

a.addToAllInstances('ap'); // === A.prototype.add('ap');
a.get(); // [ap, ai]
new A().get(); // [ap]
b.get(); // [ap]
b.prototype.get(); // [ap]

b.add('bi');
b.get(); // [ap, bi]

a.addToAllInstances('aap');
b.addToAllInstances('bp');
b.get(); // [ap, aap, bp, bi]

【讨论】:

非常好的代码!使用 getPrototypeOf 并且还忘记了实例 _data 属性。非常感谢您的出色解释和示例。正是我需要的。【参考方案2】:
 function A() 
     A.prototype._data = [];

 A.prototype.add = function(rec) 
   this._data.push(rec);
 

 A.prototype.get = function() 
   return this._data;
 

 function B() 
 B.prototype = Object.create(A.prototype,  constructor:  value: B    );

 B.prototype._data = [];

 B.prototype.get = function() 
   return A.prototype._data.concat(this._data);
   

 a.add('aa');
 b.add('bb');
 console.log(b.get()); // [aa, bb]

 a.add('aaaa');
 console.log(b.get()); // [aa, aaaa, bb]

Fiddle

【讨论】:

我很抱歉我最近编辑的问题很糟糕,a.get() 应该只返回 [aa, aaaa]。谢谢【参考方案3】:

我想我对你现在想要做什么有了更好的理解,所以我删除了我之前的答案并发布了这个。

我认为我会这样做(需要注意的是,我完全不确定如果更好理解,完全不同的方法不会更好):

function A() 
A.prototype._Adata = [];

A.prototype.add = function(rec) 
  this._Adata.push(rec);
;

A.prototype.get = function() 
  return this._Adata;
;

function B() 
B.prototype = Object.create(A.prototype,  constructor:  value: B );

B.prototype._Bdata = [];

B.prototype.add = function(rec) 
  this._Bdata.push(rec);
;
B.prototype.get = function() 
  return this._Adata.concat(this._Bdata);
  // Or: return A.prototype.get.call(this).concat(this._Bdata);
;

var a = new A();
var b = new B();

a.add('aa');
b.add('bb');
console.log(b.get()); // [aa, bb]

a.add('aaaa');
console.log(b.get()); // [aa, aaaa, bb]

Fiddle

这样,B 不会深入到 A 的内部。

【讨论】:

_Adata 不是“内部人员”吗?您可以(并且 imo 应该)使用 A 的 get @Bergi:是的,我想你可能会说它是。对我来说,这些的全部意义在于分享这些信息,所以我不认为它们是“内部的”,如果没有帮助库,调用Aget 版本会很痛苦。但我已将其添加为选项。

以上是关于javascript原型继承-共享属性的主要内容,如果未能解决你的问题,请参考以下文章

javascript 的继承

⑤创建型设计模式原型模式

javascript里面的继承怎么实现,如何避免原型链上面的对象共享

关于JavaScript的原型继承与原型链

JavaScript学习3:原型和继承

javaScript基础