frr*_*lod 2 javascript inheritance
来自codeacademy的练习:
function Penguin(name) {
this.name = "Pingy";
this.numLegs = 2;
}
// create your Emperor class here and make it inherit from Penguin
function Emperor (name){
this.name = name;
}
Emperor.prototype = new Penguin();
var emp = new Emperor("Empy");
Run Code Online (Sandbox Code Playgroud)
所以我创建了Emperor继承属性Penguin,现在我知道emp.numLegs将是2.
阅读完评论之后,我编辑了一个问题:你可以看到我在创作时给出了一个名字emp,而且emp.name确实是我的新emp的名字,即"Empy".但是name从Penguin类构造函数继承的呢?它去哪儿了?
Codecademy是初学者学习JavaScript的好方法.学习任何编程语言需要练习,Codecademy让你练习.
但有时你需要超越实践的范围并学习一些理论.阅读以下答案.它很好地解释了JavaScript中的原型继承:https://stackoverflow.com/a/8096017/783743
现在你有一个Penguin构造函数如下:
function Penguin(name) {
this.name = name;
this.numLegs = 2;
}
Run Code Online (Sandbox Code Playgroud)
然后创建一个Emperor继承自Penguin以下内容的构造函数:
function Emperor(name) {
this.name = name;
}
Emperor.prototype = new Penguin();
Run Code Online (Sandbox Code Playgroud)
请注意,您正在创建一个实例Penguin并将其分配给Emperor.prototype.因此:
Emperor.prototype.name = undefined- 这是因为你没有传递name给Penguin构造函数.如果我写的Emperor.prototype = new Penguin("Empy")那Emperor.prototype.name就是"Empy".Emperor.prototype.numLegs = 2 - 显然.现在,当你创建一个新的Emperor如下,你需要给构造函数的名称(请记住,你继承undefined从Penguin作为名字).因此:
var emp = new Emperor("Empy");
Run Code Online (Sandbox Code Playgroud)
那是旧学校的方法.
现在JavaScript程序员使用Object.create并call继承另一个构造函数.让我用一个例子来解释一下:
function Emperor(name) {
Penguin.call(this, name);
}
Emperor.prototype = Object.create(Penguin.prototype);
Emperor.prototype.constructor = Emperor;
Run Code Online (Sandbox Code Playgroud)
这种方法比旧学校方法有几个优点:
Penguin使用实例new Penguin()并且不向它传递任何参数.这也可以防止基本构造函数的不必要的初始化,直到实际调用派生的构造函数.PenguinObject.create(Penguin.prototype)this.name = name我们不再在派生的构造函数中写入,而是使用Penguin.call(this, name)它来为我们调用基础构造函数.这种模式称为mixin,如果基本构造函数需要在运行时初始化或需要维护自己的状态信息,则非常有用.请注意,我们还添加了一个附加声明Emperor.prototype.constructor = Emperor.这是因为它prototype是一个非常特殊的属性,存在于所有函数中.它指向一个具有非常特殊constructor属性的对象,该属性指向函数本身.通过设置Emperor.prototype其他东西,我们失去了这个属性.因此我们再次设置它.
这两个例子中的净效果是相同的.但是对于更复杂的代码,使用新方法要好得多.快乐学习JavaScript.
我假设您想知道为什么必须在构造name函数中Emperor和作为参数this.name = name;内部提供.
JavaScript中的原型继承非常简单,没有隐藏的魔法.你之间的唯一连接Emperor,并Penguin在这一行:
Emperor.prototype = new Penguin();
Run Code Online (Sandbox Code Playgroud)
Emperor.prototype现在是一个实例Penguin,但它可能是任何对象.该函数 Emperor对该函数一无所知Penguin,因此它不会神奇地调用Penguin.
当你调用一个function(Func)时new,它所做的只是创建一个新的空对象,其原型是函数prototypeproperty(Func.prototype).此对象将成为this构造函数内的值,如果没有返回其他对象,将隐式返回该对象.
但是从Penguin类构造函数继承的名称怎么样?它去哪儿了?
它Emperor.prototype是每个Emperor实例name属性的属性并被其遮蔽.
看看我的答案,我在这里创建了一些很好的ASCII图表来解释实例和它们的原型之间的关系.
注意: Emperor.prototype = new Penguin();实际上不是建立继承的好方法.如果Penguin 需要 参数,会发生什么?什么会通过?
这时你其实并不想创建的新实例Penguin,你只需要挂钩Penguin的prototype成原型链.您可以通过以下方式轻松完成Object.create:
Emperor.prototype = Object.create(Penguin.prototype);
Emperor.prototype.constructor = Emperor;
Run Code Online (Sandbox Code Playgroud)
但是新Emperor物品不再具有numLegs属性了.这就是为什么你必须Penguin在每个新Emperor实例上调用它,就像在其他语言中一样super():
function Emperor (name){
Penguin.call(this, name);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1871 次 |
| 最近记录: |