Das*_*alo 170 javascript oop inheritance constructor prototype-programming
我是JavaScript OOP的新手.你能解释下面的代码块之间的区别吗?我测试了两个块都有效.什么是最佳实践,为什么?
第一块:
function Car(name){
this.Name = name;
}
Car.prototype.Drive = function(){
console.log("My name is " + this.Name + " and I'm driving.");
}
SuperCar.prototype = new Car();
SuperCar.prototype.constructor = SuperCar;
function SuperCar(name){
Car.call(this, name);
}
SuperCar.prototype.Fly = function(){
console.log("My name is " + this.Name + " and I'm flying!");
}
var myCar = new Car("Car");
myCar.Drive();
var mySuperCar = new SuperCar("SuperCar");
mySuperCar.Drive();
mySuperCar.Fly();Run Code Online (Sandbox Code Playgroud)
第二块:
function Car(name){
this.Name = name;
this.Drive = function(){
console.log("My name is " + this.Name + " and I'm driving.");
}
}
SuperCar.prototype = new Car();
function SuperCar(name){
Car.call(this, name);
this.Fly = function(){
console.log("My name is " + this.Name + " and I'm flying!");
}
}
var myCar = new Car("Car");
myCar.Drive();
var mySuperCar = new SuperCar("SuperCar");
mySuperCar.Drive();
mySuperCar.Fly();Run Code Online (Sandbox Code Playgroud)
为什么笔者的增加Drive和Fly方法使用prototype,并没有宣布他们的this.Drive内部方法Car类和this.Fly在SuperCar类?
为什么SuperCar.prototype.constructor需要重新开始SuperCar?设置constructor时prototype是否覆盖了属性?我评论了这一行并没有改变.
为什么要Car.call(this, name);在SuperCar构造函数中调用?Car当我这样做时,属性和方法不会被"继承"
var myCar = new Car("Car");
Run Code Online (Sandbox Code Playgroud)
Tun*_*yen 140
要添加到Norbert Hartl的答案中,不需要SuperCar.prototype.constructor,但是有些人使用它作为获取对象的构造函数的便捷方式(在这种情况下为SuperCar对象).
从第一个例子开始,Car.call(this,name)在SuperCar构造函数中,因为当你这样做时:
var mySuperCar = new SuperCar("SuperCar");
Run Code Online (Sandbox Code Playgroud)
这就是JavaScript的作用:
请注意JavaScript没有为您调用Car.原型就像它们一样,你没有为SuperCar设置的任何属性或方法都将在Car中查找.有时这很好,例如SuperCar没有Drive方法,但它可以共享Car的方法,因此所有SuperCars都将使用相同的Drive方法.其他时候你不想分享,比如每个SuperCar都有自己的名字.那么如何将每个SuperCar的名称设置为它自己的东西呢?你可以在SuperCar构造函数中设置this.Name:
function SuperCar(name){
this.Name = name;
}
Run Code Online (Sandbox Code Playgroud)
这有效,但等一下.我们不是在Car构造函数中做同样的事情吗?不想重复自己.由于Car已经设置了名称,我们只需要调用它.
function SuperCar(name){
this = Car(name);
}
Run Code Online (Sandbox Code Playgroud)
哎呀,你永远不想改变特殊this对象的引用.还记得4个步骤吗?挂在JavaScript给你的对象上,因为这是保持SuperCar对象和Car之间宝贵的内部原型链接的唯一方法.那么我们如何设置Name,而不是重复自己并且不丢弃我们新鲜的SuperCar对象JavaScript花了这么多特别的努力为我们做准备?
两件事情.一:this灵活的意义.二:汽车是一种功能.可以调用Car,而不是使用原始的,新鲜的实例化对象,而是使用SuperCar对象.这为我们提供了最终解决方案,这是您问题中第一个示例的一部分:
function SuperCar(name){
Car.call(this, name);
}
Run Code Online (Sandbox Code Playgroud)
作为一个函数,允许使用函数的调用方法调用Car ,这会将thisCar内部的含义更改为我们正在构建的SuperCar实例.普雷斯托!现在每个SuperCar都有自己的Name属性.
总结一下,Car.call(this, name)在SuperCar构造函数中为每个新的SuperCar对象提供了它自己唯一的Name属性,但没有复制已经在Car中的代码.
一旦你理解了它们,原型并不可怕,但它们根本不像经典的类/继承OOP模型.我在JavaScript中写了一篇关于原型概念的文章.它是为使用JavaScript的游戏引擎编写的,但它与Firefox使用的JavaScript引擎相同,因此它应该都是相关的.希望这可以帮助.
Nor*_*rtl 82
这两个块的不同之处在于,在第一个示例中Drive()仅存在一次,而在第二个方法Drive()中将存在每个实例(每次执行new Car()此功能时drive()将再次创建).或者说不同的是第一个使用原型来存储函数而第二个使用构造函数.函数的查找是构造函数,然后是原型.因此,对于Drive()它的查找,无论它是在构造函数中还是在原型中,都会找到它.使用原型更有效,因为通常每种类型只需要一次函数.
newjavascript中的调用会自动在原型中设置构造函数.如果要覆盖原型,则必须手动设置构造函数.
javascript中的继承没有什么比这更好的了super.因此,如果你有一个子类,那么调用超级构造函数的唯一机会就是它的名字.
诺伯特,你应该注意到你的第一个例子就是道格拉斯·克罗克福德所谓的伪经典继承.关于此事需要注意的事项:
最后,我想提一下我在这里有几个TDD JavaScript继承代码的例子:TDD JavaScript继承代码和论文我很想得到你的反馈,因为我希望改进它并保持开源.目标是帮助经典程序员快速掌握JavaScript,并补充Crockford和Zakas书籍的研究.
| 归档时间: |
|
| 查看次数: |
45808 次 |
| 最近记录: |