我有Java背景,最近我一直在尝试JavaScript继承。我开始写一些对象,在阅读了一些例子后,我发现了最适合我的代码风格。
这就是我所拥有的:
var Class = function() {};
Class.extend = function(p_constructor) {
var Superclass = this;
// the following line confuses me
p_constructor.prototype = Object.create(Superclass.prototype);
p_constructor.prototype.constructor = p_constructor;
p_constructor.extend = Superclass.extend;
return p_constructor;
};
所以现在当我想定义一个扩展Class I的对象时,只需输入:
var Person = Class.extend(function(p_firstName, p_lastName) {
this.firstName = p_firstName;
this.lastName = p_lastName;
});
以下将是真实的:
var p = new Person('john', 'smith');
p instanceof Person; // true
p instanceof Class; // true
我只是很难理解Class.extend
函数中以下几行之间的有效差异:
/* 1) */ p_constructor.prototype = new Superclass();
/* 2) */ p_constructor.prototype = Superclass.prototype;
/* 3) */ p_constructor.prototype = Object.create(Superclass.prototype);
/* 4) */ p_constructor.prototype = Object.create(Superclass);
我确实意识到如果某些超级构造函数抛出错误,使用第1行并不是很明智,但是第2,3和4行之间究竟有什么区别?
答案 0 :(得分:6)
回答我自己的问题:
/* 1) */ p_constructor.prototype = new Superclass();
就像我说的那样,使用它并不是很明智,因为它实际上创建了整个Superclass对象。原型继承的全部意义在于共享原型对象,因此可以避免冗余的功能(有时是对象)定义。
/* 2) */ p_constructor.prototype = Superclass.prototype;
如果您确定构造函数的原型永远不会被第三方修改,那就没关系。假设使用您的类的人想要为其原型添加额外的功能。更改p_constructor的原型将直接影响超类的原型,并可能在超类的行为中引入错误。因此,使用下一行代码:
/* 3) */ p_constructor.prototype = Object.create(Superclass.prototype);
这会创建一个新对象(实例),其原型(实际上是__proto__
变量)设置为Superclass'原型。对p_constructor.prototype
的任何更改现在都不会更改超类的行为。
/* 4) */ p_constructor.prototype = Object.create(Superclass);
上面的行有效,但没有意义,因为它只将原型设置为Superclass的构造函数。
另外,以下一行也让我感到困惑:
p_constructor.prototype.constructor = p_constructor;
它对p_constructor的行为没有区别,它只对实例化对象中的构造函数进行引用。一个巧妙的技巧是将超类添加到原型中:
p_constructor.prototype.superclass = Superclass;
然后下面的代码就可以了:
function Constructor(p_params) {
// call constructor of the superclass
this.superclass(p_params);
}