Javascript 变量属性的继承性
来自codeacademy的练习:Javascript 变量属性的继承性,javascript,inheritance,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 em
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");
所以我让emper
继承Penguin
的属性,现在我知道emp.numLegs
将是2
阅读评论后,我编辑了问题:
正如您所见,我在创建
emp
时给出了一个名称,emp.name
将确实是我的新emp的名称,即“Empy”。但是继承自企鹅类构造函数的名称如何?它到哪里去了?我想您想知道为什么必须提供name
作为emperon
和this.name=name的参数代码>在构造函数内部
JavaScript中的原型继承非常简单,没有隐藏的魔力。您在emperon
和Penguin
之间提供的唯一连接如下:
Emperor.prototype = new Penguin();
Emperor.prototype
现在是Penguin
的一个实例,但它可以是任何对象。函数emperon
对函数Penguin
一无所知,因此它不会神奇地调用Penguin
使用new
调用函数(Func
)时,它所做的只是创建一个新的空对象,其原型是functionsprototype
属性(Func.prototype
)。此对象将成为构造函数中的This
值,如果没有返回其他对象,则将隐式返回
但是从企鹅类构造函数继承的名称呢?它去哪里了
它是emperon.prototype
的一个属性,并且被每个emperon
实例的name
属性隐藏
看看我在哪里创建了一些漂亮的ASCII图表,解释了实例与其原型之间的关系
注意:employer.prototype=new Penguin()
实际上不是建立继承的好方法。如果企鹅
需要一个参数,会发生什么?什么会过去
此时您实际上不想创建一个新的Penguin
实例,您只想将Penguin
的prototype
连接到prototype链中。使用对象可以轻松完成此操作。创建:
Emperor.prototype = Object.create(Penguin.prototype);
Emperor.prototype.constructor = Emperor;
但是新的Emperor
对象将不再具有numLegs
属性。这就是为什么您必须在每个新的empire
实例上调用Penguin
,就像在其他语言中使用super()
一样:
调用new Penguin()
时,此方法将创建一个对象并返回该对象的原型
在执行prototype inhertance时,您唯一要做的就是首先创建一个新的Penguin
对象,并将这些值放入Emperor
的prototype中。现在,当您创建一个新的emperon
对象时,原型已经设置为Penguin
的值。要覆盖这些,您需要在新构造函数中再次设置它们
JavaScript中的固有性与其他语言非常不同
代码示例:
function Penguin(name) {
this.name = name;
this.legs = 2;
}
function Emperor(name) {
this.name = name;
}
Emperor.prototype = new Penguin();
/**
* The prototype of Emperor now contains:
*
{
"name": undefined,
"legs": 2
}
*
* Because you didn't add an argument to the constructor of `Penguin`
*/
var e = new Emperor('foo');
// The name property will get overriden with 'foo'
Penguin
对象在创建时也需要将名称传递到name
参数中。因此,当您创建类型为Penguin
的新对象时,必须传递名称。类似地,由于emperon
继承自Penguin
对象,因此必须在构造函数中传递值,以便如果希望执行与基类Penguin
中不同的处理,可以在子类构造函数中定义它。但是empire
可以是任何类型的对象,因为它没有关于Penguin
定义的信息
如果在类“皇帝”的定义中删除了行
this.name = name;
然后,您可以在构造函数中传递任何变量,仍然可以获得超级构造函数中定义的值“Pingy”
如果你加上一行
Penguin.call(this, name) ;// As to call super class instance
然后使用numLegs
as 2将值正确地传递到新对象上,Codecademy也是初学者学习JavaScript的好方法。学习任何编程语言都需要练习,Codecademy让你练习
然而,有时你需要超越实践的范围,学习一些理论。阅读下面的答案。它很好地解释了JavaScript中的原型继承:
现在您有了一个Penguin
构造函数,如下所示:
function Penguin(name) {
this.name = name;
this.numLegs = 2;
}
然后创建一个继承自企鹅的emperon
构造函数:
function Emperor(name) {
this.name = name;
}
Emperor.prototype = new Penguin();
请注意,您正在创建一个Penguin
的实例,并将其分配给emperon.prototype
。因此:
employer.prototype.name=undefined
-这是因为您没有向Penguin
构造函数传递任何name
。如果我写的是emper.prototype=new Penguin(“Empy”)
,那么emper.prototype.name
将是“Empy”
employer.prototype.numLegs=2
-显然
现在,当您按照如下方式创建一个新的emperon
时,您需要给构造函数一个名称(请记住,您是从Penguin
继承undefined
作为名称)。因此:
那是老派的方法。
现在JavaScript程序员使用Object.create
和call
从另一个构造函数继承。让我举例说明:
function Emperor(name) {
Penguin.call(this, name);
}
Emperor.prototype = Object.create(Penguin.prototype);
Emperor.prototype.constructor = Emperor;
与传统方法相比,这种方法有几个优点:
我们没有使用new Penguin()
创建Penguin
的新实例,也没有向其传递任何参数,而是使用Object.create(Penguin.prototype)
继承Penguin
的原型成员。这还可以防止在deriv之前对基本构造函数进行不必要的初始化
var emp = new Emperor("Empy");
function Emperor(name) {
Penguin.call(this, name);
}
Emperor.prototype = Object.create(Penguin.prototype);
Emperor.prototype.constructor = Emperor;