JavaScript原型继承解决方法

时间:2011-10-07 00:45:09

标签: javascript inheritance prototype-programming

以下是一个例子:

var Box = function() {
    this.id = generateUniqueId();
};
Box.prototype = {
    add:function(parent) {
        parent.appendChild(this.elm);
    }
};

var NewBox = function() {
    this.newThing = true;
};
NewBox.prototype = new Box();
NewBox.prototype.remove = function() {
    this.elm.parentNode.removeChild(this.elm);
};

var a = new NewBox();
var b = new NewBox();
alert(a.id); // alerts 0
alert(b.id); // also alerts 0! :@

我想a和b(基本上每次创建NewBox)都有自己的id。我理解NewBox正在使用原型继承,因此继承自id生成的Box的单个实例,但我希望每个NewBox得到自己的id,而不必在NewBox构造函数中明确说明。

也许这是不可能的,或者我做错了什么,所以请帮忙!

非常感谢!

3 个答案:

答案 0 :(得分:6)

在您的示例中,只有在设置Box对象时才会执行NewBox.prototype构造函数。

您可以通过使用Function.prototype.apply方法调用Box内的NewBox构造函数来解决此问题,设置this值并转发所有参数值,例如:

//..
var NewBox = function() {
    Box.apply(this, arguments);
    this.newThing = true;
};
//..

var a = new NewBox();
var b = new NewBox();

// assuming your `generateUniqueId` function
// increments a number

alert(a.id); // will alert 1
alert(b.id); // will alert 2

现在,每次调用NewBox构造函数来创建新的对象实例(new NewBox();)时,它都会调用Box函数来应用它的所有逻辑。这将帮助您避免一遍又一遍地重复父构造函数的逻辑。

apply用于调用“父”构造函数,将this值设置为NewBox构造函数创建的对象实例,并传递提供给的所有参数这个功能。

您的示例还显示了一个常见问题,当您通过NewBox.prototype = new Box();表达继承关系时Box构造函数被调用且有副作用,此新对象将被初始化并且您的generateUniqueId函数将首次执行,如果你想避免这种情况,你需要使用临时构造函数,只需要创建一个继承自Box.prototype的新对象,或者使用新的ECMAScript 5 {{1}用于相同目的的方法,例如:

Object.create

或者:

function inherit(o) {
  function Tmp() {}
  Tmp.prototype = o;
  return new Tmp();
}

//.....
NewBox.prototype = inherit(Box.prototype);

通过这种方式,您可以在不首次运行NewBox.prototype = Object.create(Box.prototype); 构造函数的情况下表达相同的继承层次结构,从而避免可能导致的任何副作用。

最后但并非最不重要的是,每当你替换一个函数的prototype属性时,总是建议你恢复这个新原型对象的Box属性,否则会指向错误的函数。

在您的示例中,由于您使用constructor的新实例替换NewBox.prototypeBox属性将指向NewBox.prototype.constructor,(您的实例会受到影响,例如Box)而不是您期望的a.constructor === Box; // true,我们需要将其设置回来,例如:

NewBox

您可以将这些细节抽象为函数,就像我在上面的NewBox.prototype = someObject; // as any of the examples above NewBox.prototype.constructor = NewBox; 函数中所做的那样:

inherit

答案 1 :(得分:2)

  

也许这是不可能的,或者我做错了什么,所以请帮忙!

你做错了什么。

如果您想要特定于实例的值,请在构造函数中初始化它们,而不是原型。

答案 2 :(得分:1)

Matt Ball有正确的想法。而是尝试:

var Box = (function(){ 
    var numberOfBoxes = 0;
    function() {
        this.id = numberOfBoxes++;
    }
})();

或者,如果您希望所有(不同)类具有唯一ID:

var generateUniqueID = (function(){
    var runningCount = 0;
    return function (){
        return runningCount++;
    }
})();

var Box = function() {
    this.id = generateUniqueId();
};

var NewBox = function() {
    this.id = generateUniqueId();
    this.newThing = true;
};