【问题标题】:JS Prototypal Inheritance: childs use the same parent properties?JS原型继承:孩子使用相同的父属性?
【发布时间】:2013-04-03 17:23:43
【问题描述】:

假设我有 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 时,它们每个都共享相同的 handlers 属性:

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

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

我在这里缺少什么?我理解每个testPlayer 的原型与我在描述子类时创建的new player 对象相同。但是有没有办法让所有的 testPlayer 拥有自己的一组处理程序?

【问题讨论】:

    标签: javascript prototypal-inheritance prototype-programming


    【解决方案1】:

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

    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);
    }
    

    有趣的事实

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

    【讨论】:

    • +1 表示“另一种解决方案”,这看起来是最有用的。
    • 我同意,这是一个完全有效的编程范式。烦人的部分是你必须在每个使用 handlers 的方法中添加这样的检查。
    • 您可以从构造函数调用一个init 方法,然后从那里执行。请注意,如果您正在修改原型上的对象(或数组)的属性,这只是一个问题。如果您尝试分配给原型上的属性,则会自动创建一个本地阴影属性(您不能从实例分配给原型属性)。
    【解决方案2】:

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

    testPlayer.prototype = new player();
    

    您将一个全新的player 对象的每个属性添加到testPlayer.prototype,并且包括 handlers

    因此,每个testPlayer 对象中都有一个handlers 属性,当您将属性添加到handlers 时,您将属性添加到原型中的对象,而不是testPlayer 对象。

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

    为了安全起见,定义:

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

    【讨论】:

      猜你喜欢
      • 2011-05-27
      • 2013-02-01
      • 1970-01-01
      • 2016-02-15
      • 1970-01-01
      • 2023-03-16
      • 2023-02-18
      • 2011-07-31
      • 2020-12-04
      相关资源
      最近更新 更多