javascript - 了解 JavaScript 中的原型(prototype)继承

标签 javascript oop inheritance constructor prototype-programming

我是 JavaScript OOP 的新手。您能解释一下以下代码块之间的区别吗?我进行了测试,两个 block 都可以工作。最佳做法是什么?为什么?

第一 block :

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();

第二 block :

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();

为什么作者使用prototype添加DriveFly方法,并没有声明为this.Drive Car 类中的 方法和 SuperCar 类中的 this.Fly 方法?

为什么需要将SuperCar.prototype.constructor设置回SuperCar?设置 prototype 时是否会覆盖 constructor 属性?我注释掉了这一行,没有任何改变。

为什么在 SuperCar 构造函数中调用 Car.call(this, name);?当我这样做时,Car 的属性和方法不会被“继承”

var myCar = new Car("Car");

最佳答案

添加到 Norbert Hartl's answer , SuperCar.prototype.constructor 不是必需的,但有些人将其用作获取对象(本例中为 SuperCar 对象)的构造函数的便捷方式。

从第一个例子开始,Car.call(this, name) 就在 SuperCar 构造函数中,因为当你这样做时:

var mySuperCar = new SuperCar("SuperCar");

这就是 JavaScript 的作用:

  1. 一个新的空白对象被实例化。
  2. 新对象的内部原型(prototype)设置为 Car。
  3. SuperCar 构造函数运行。
  4. 返回完成的对象并在 mySuperCar 中设置。

请注意 JavaScript 没有为您调用 Car。就原型(prototype)而言,您没有为 SuperCar 设置的任何属性或方法都将在 Car 中查找。有时这很好,例如SuperCar 没有 Drive 方法,但它可以共享 Car 的方法,因此所有 SuperCar 将使用相同的 Drive 方法。其他时候你不想分享,比如每辆 super 跑车都有自己的名字。那么如何将每辆 SuperCar 的名称设置为自己的东西呢?您可以在 SuperCar 构造函数中设置 this.Name:

function SuperCar(name){
    this.Name = name;
}

这可行,但请稍等。我们不是在 Car 构造函数中做了完全相同的事情吗?不想重蹈覆辙。既然 Car 已经设置了名字,我们就叫它吧。

function SuperCar(name){
    this = Car(name);
}

哎呀,您永远不想更改特殊的 this 对象引用。还记得这4个步骤吗?捕获 JavaScript 给你的那个对象,因为它是保持 SuperCar 对象和 Car 之间宝贵的内部原型(prototype)链接的唯一方法。那么我们如何设置Name,又不重复我们自己,又不丢掉我们新鲜的SuperCar对象JavaScript花了这么多特别的精力来为我们准备呢?

两件事。一:this的含义灵活。二:汽车是一种功能。可以调用 Car,而不是使用原始的、新鲜的实例化对象,而是使用例如 SuperCar 对象。这为我们提供了最终解决方案,这是您问题中第一个示例的一部分:

function SuperCar(name){
    Car.call(this, name);
}

作为一个函数,允许使用函数的 call method 调用 Car ,这将 Car 中 this 的含义更改为我们正在构建的 SuperCar 实例。快!现在每辆 SuperCar 都有自己的 Name 属性。

总之,SuperCar 构造函数中的 Car.call(this, name) 为每个新的 SuperCar 对象提供了它自己唯一的 Name 属性,但不会复制 Car 中已有的代码。

一旦理解了原型(prototype),它们就不可怕了,但它们一点也不像经典的类/继承 OOP 模型。我写了一篇关于 the prototypes concept in JavaScript 的文章.它是为使用 JavaScript 的游戏引擎编写的,但它与 Firefox 使用的 JavaScript 引擎相同,因此应该都是相关的。希望这会有所帮助。

关于javascript - 了解 JavaScript 中的原型(prototype)继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/892595/

相关文章:

java - 从 java 方法返回两个值

perl - 旧 TPJ 文章中的 8 queen 问题缺少到主模块 Queen 的链接

python - 使用 python 类中的属性覆盖属性

c++ - 如果基类没有成员,派生 C++ 类的大小是多少?

javascript - 防止多次绑定(bind)一个函数

javascript - react 绑定(bind)问题和内存管理

javascript数字01和1之间的区别

javascript - 方法参数的动态变量

java - 在 Java 中使用泛型时出现空指针异常

c# - 通过层次结构的 PostSharp 和方面继承