2012-12-29 37 views
4

正当我认为自己对原型继承在JavaScript中的工作方式持保留态度时,遇到了一个我以前没有考虑过的问题。防止构造函数的多个实例共享相同的原型属性

看看下面的简单的JavaScript代码:

var Observable = function() { 
    this.events = []; 
}; 

Observable.prototype.addEvent = function (e) { 
    this.events.push(e); 
}; 

var Model = function() {}; 
Model.prototype = new Observable(); 

var appModel = new Model(); 
var taskModel = new Model(); 

appModel.addEvent('Hello'); 
taskModel.addEvent('World'); 

寻找在任appModel.eventstaskModel.events产生相同的数组:['Hello', 'World']。我期待的是每个新的Model都有自己的events阵列,尽可能清洁。的Model以下实施工作:

var Model = function() { 
    this.events = []; 
}; 
Model.prototype = new Observable(); 

然而,随着越来越多的属性添加到Observable这变得更加难以处理。我以为我可以解决这个问题如下:我敢肯定,你们谁在JavaScript中更有经验实现,这将引发一个错误

var Model = function() { 
    this.prototype.constructor.apply(this, arguments); 
}; 
Model.prototype = new Observable(); 

Alhtough:TypeError: Cannot read property 'constructor' of undefined

总之,我正在寻找一种方法,让每个新的Model继承Observable的属性,并为每个Model拥有自己的events。我意识到这是非常类的,但我想知道如何仅使用基于JavaScript原型的继承来完成此操作。

值得注意的是,我看过Dean Edward的Base.js。以下作品:

var Observable = Base.extend({ 
    constructor: function() { 
    this.events = []; 
    }, 
    addEvent: function (e) { 
    this.events.push(e); 
    } 
}); 

var Model = Observable.extend({ 
    constructor: function() { 
    this.base(); 
    } 
}); 

var appModel = new Model(); 
var taskModel = new Model(); 

appModel.addEvent('Hello'); 
taskModel.addEvent('World'); 

但是下面

var Observable = Base.extend({ 
    events: [], 
    addEvent: function (e) { 
    this.events.push(e); 
    } 
}); 

var Model = Observable.extend({ 
    constructor: function() { 
    this.base(); 
    } 
}); 

var appModel = new Model(); 
var taskModel = new Model(); 

appModel.addEvent('Hello'); 
taskModel.addEvent('World'); 

除了一点,我想学习如何使用JavaScript的原型不使用类库做到这一点。

+0

问题是.....? – HMarioD

+0

我有这个确切的问题,试图建立一个Observable类。当然,我们不能成为第一个在JS中构建这种类型的东西的人? –

回答

0

我在这里明白是要每个实例有各自独立的事件数组,如果是遵循了答案:

function Model(){ 
    this.events = []; 
    this.addEvent = function(eventName){ 
    this.events.push(eventName); 
    }; 
    this.getEvents = function(){ 
    return this.events; 
    } 
} 

var m1 = new Model; 
var m2 = new Model; 
m1.addEvent("eve-1"); 
m2.addEvent("eve-2"); 
m1.getEvents(); //["eve-1"] 
m2.getEvents(); //["eve-2"] 

在你的情况,你是直接因此添加事件到prototype没有实例他们在所有的情况下,加...我希望这将有助于

+0

我想要做的是在共享该共同行为的多种类型的对象中获得共同行为。虽然我没有创建任何东西,只是'模型',目的是创造更多类型共享相同的功能,但不是相同的事件。保留'Observable'原型上的方法对我来说很有意义,但我想要一种方法,在我创建的每个构造函数中不必声明this.events = [];'。 – user1937128

+0

所有那些需要共同点的东西都应该添加到原型中,并且应该像上面那样添加这些变量事件... –

0

我试过这解决我的问题:

var Model = function() { 
    this.prototype.constructor.apply(this, arguments); 
}; 
Model.prototype = new Observable(); 

的交流图阿尔,解决方案是这样的:

var Model = function() { 
    Model.prototype.constructor.apply(this, arguments); 
}; 
Model.prototype = new Observable(); 

这会给每个Model自己的events阵列,以及给每个ModelObservable构造函数创建任何其他属性。这里的小开销是Model.prototype.events是一个永远不会被访问的空数组。

0

您的第一位代码导致Model的每个实例拥有共同的events数组的原因是因为它们具有对Observable的单个常见实例的原型引用。换句话说,通过做

Model.prototype = new Observable(); 

你基本上是告诉JavaScript的“使Model行为所有实例像此特定实例的Observable”。

有几种不同的方法可以在JavaScript中正确执行原型继承。如果您可以使用最近标准化的ECMAScript 6,您可以使用专门为此目的而设计的新型关键字classextends

class Observable { 
    constructor() { 
     this.events = []; 
    } 

    addEvent() { 
     this.events.push(e); 
    } 
} 

class Model extends Observable { 
    // Model definition 
}; 

不幸的是,对ECMAScript 6的支持仍然是isn't great。 ECMAScript 5增加了Object.create,因为(至少据我所知),它一直是继承的首选方法。

var Observable = function() { 
    this.events = []; 
}; 

Observable.prototype.addEvent = function (e) { 
    this.events.push(e); 
}; 

var Model = function() { 
    Observable.call(this); 
}; 
Model.prototype = Object.create(Observable.prototype); 

MDN有一个很不错的article on OOP in JavaScript使用这种技术。

相关问题