5

假设我有 Player 对象:

var player = function(name) {
    this.handlers = {};
}

player.prototype.on = function(event, callback) {
    if (!this.handlers[event]) {
        this.handlers[event] = [];
    }
    this.handlers[event].push(callback);
}

效果很好,我可以创建玩家,每个玩家都有自己的一组处理程序。现在假设我需要继承自player

var testPlayer = function(name) {
    this.name = name;
};

testPlayer.prototype = new player();

现在,当我创建testPlayer's 时,它们每个都共享相同的handlers属性:

var adam = new testPlayer('Adam');
adam.on('test', function(){});

var eve = new testPlayer('Eve');
// eve.handlers == {'test':<function>}

我在这里想念什么?我明白每个testPlayer的原型都是new player我在描述子类时创建的同一个对象。但是有没有办法让所有的 testPlayers 拥有自己的一组处理程序?

4

2 回答 2

5

对于那些习惯于经典继承的人来说,这确实看起来很奇怪,但这就是原型继承的工作方式。要为每个实例提供一个单独的处理程序对象,您需要在子构造函数上指定一个。这将隐藏原型的同名属性:

var testPlayer = function(name) {
    this.name = name;
    this.handlers = {};
};

testPlayer.prototype = new player();

on另一种解决方案是根据您的方法按需创建此阴影属性:

player.prototype.on = function(event, callback) {
    // Check for a handlers property on the instance
    if(!this.hasOwnProperty('handlers') {
        this.handlers = {};
    }
    if (!this.handlers[event]) {
        this.handlers[event] = [];
    }
    this.handlers[event].push(callback);
}

有趣的事实

如果您正在修改原型上的对象(或数组)的属性,这只是一个问题。如果您尝试分配给原型上的属性,则会自动创建一个本地阴影属性(您不能从实例分配给原型属性)。

于 2013-04-03T17:29:20.117 回答
1

这里的问题是这是在构造函数handlers中添加的一个属性,所以当你这样做时

testPlayer.prototype = new player();

您正在将一个全新player对象的每个属性添加到testPlayer.prototype,其中包括 handlers.

所以,handlers每个testPlayer对象都有一个属性,当你添加一个属性时,handlers你是在将属性添加到原型中的对象,而不是testPlayer对象。

简而言之,在调用该on方法时,您将属性添加到testPlayer.prototype.handlers,而不是adam.handlerseve.handlers

为了安全起见,定义:

var testPlayer = function(name) {
    this.name = name;
    this.handlers = {};
};
于 2013-04-03T17:33:43.490 回答