【问题标题】:Javascript Inheritance ; call and prototypeJavascript 继承;调用和原型
【发布时间】:2013-02-22 08:02:16
【问题描述】:

要在Javascript中实现继承,一般做以下2个步骤;

假设我有一个基类“动物”

var Animal = function(name){
this.name = name;
}

我现在想从中派生一个子类“Dog”。所以我想说

var Dog = function(name) {
   Animal.call(this,name);
}

所以我从派生类构造函数中调用我的父类构造函数。 第二步,设置原型如下;

Dog.prototype = new Animal();

现在我可以从派生类 Dog 中访问任何基本的“动物”类属性。

所以我的问题是为什么这两个步骤是必要的? 如果我们只是使用

调用基类构造函数
Animal.call(this,name);

这还不足以实现继承吗?

为什么我们需要使用Dog.prototype = new Animal();设置原型属性?

我想了解以上 2 个步骤中的每一个的作用是什么?

【问题讨论】:

  • 你在这里没有任何东西可以继承
  • 因为Animal也可以使用原型链继承。简单地调用父构造函数不会保留该继承链。
  • 是不是说 call() 只是从基类继承属性,而第二步(设置原型)从基类继承方法?
  • @testndtv call() 不执行继承,它只是向this 添加新成员(属性或方法),而new 继承父类原型的任何成员。有关详细信息,请参阅我的答案:)

标签: javascript jquery inheritance prototypal-inheritance


【解决方案1】:

一个代码示例值一千字:)

var Animal = function(name) {
    this.name = name;
}
Animal.prototype.run = function () {
    // do something
};
var Dog = function(name) {
   Animal.call(this, name);
}

var dog = new Dog('Puppy');
typeof dog.name; // "string"
typeof dog.run; // "undefined"
dog instanceof Animal; // false
dog instanceof Dog; // true

Dog.prototype = new Animal();

var dog = new Dog('Puppy');
typeof dog.name; // "string"
typeof dog.run; // "function"
dog instanceof Animal; // true
dog instanceof Dog; // true

如您所见,如果不使用Dog.prototype = new Animal();Animal.prototype 成员将不会被继承。此外,Dog 实例不会被视为Animal 的实例。

【讨论】:

    【解决方案2】:

    这里我们定义Animal的构造函数

    var Animal = function(name){
       this.name = name;
    }
    

    然后定义Dog的构造函数,并在其中调用Animal的构造函数。就像我们在基于类的面向对象设计中所做的super() 一样。

    var Dog = function(name) {
       Animal.call(this,name);
    }
    

    然后我们通过使用原型中定义的方法来构建Dog的原型 Animal。这里它不会克隆 Animal 中的方法,但在 DogAnimal 之间设置了一个链接,通过它重新使用 Animal 中的方法

    Dog.prototype = new Animal();
    

    并继续扩展它添加更多方法

    Dog.prototype.showName = function(){
         // do something
    }
    

    【讨论】:

      【解决方案3】:

      首先要了解的是,在 JavaScript 中没有经典的继承,这是我们从 Java、C# 等 C 语言中知道的机制。在 JavaScript 中,可以通过使用原型继承来实现代码重用。我们唯一拥有的是对象,即存活且不需要实例化的代码块。例如:当在对象上调用函数时(如方法),检查当前对象是否知道该函数。如果未找到,引擎将其称为原型(这是另一个对象)并检查函数名称是否已知并且可以调用。当没有找到时,它的原型被调用等等。因此,设置对象的原型可以编排原型链。

      回答您的问题:没有什么是必要的,由您决定。代码重用是您想要的,而继承是您可以实现这一点的方式(Stoyan Stefanov - JavaScript 模式)。在 JavaScript 中,有更多的方法可以重用代码。

      此外,this 绑定到当前上下文,并不总是当前对象。

      【讨论】:

      • 所以当你说,当前对象被检查函数是否已知......如果不是,它的原型被调用等等......所以我们可以为任何类型的对象设置原型。 ..如果我检查 myObject1 上的方法 myMethod1() 并且如果没有找到,我可以在 myObject2 上进行下一次搜索...即我以某种方式将 myObject1 的原型(或父对象)设置为 myObject2...我们可以举个例子吗...
      • 哈!你明白了!设置对象原型很简单:myobject.prototype = myobject2
      • 那么与设置'proto'链接myobject._proto = myobject2一样吗(但'proto'根本无法访问Firefox 以外的浏览器)
      • 你应该忘记'proto' :) 但它等同于原型。在这里看看这个主题是多么令人困惑:(stackoverflow.com/questions/650764/…)。我的意思是不需要理解原型继承。
      【解决方案4】:

      第二步帮助你继承原型方法。假设我们有更复杂的类:

      function Animal(name) {
        this.name = name;
      }
      
      // shared method
      Animal.prototype.say = function () {
        alert( this.name );
      };
      
      function Dog() {
        Animal.apply(this, arguments);
      }
      
      Dog.prototype = new Animal();
      
      
      var dog = new Dog('Cooper');
      // method has been inherited
      dog.say(); // alerts 'Cooper'
      

      你可以试试here

      【讨论】:

        【解决方案5】:

        在 javascript 中没有类,也没有子类。

        调用并应用在不同的“this”上下文中执行函数。您的示例代码中的内容是不需要的。

        //Create your constructor function:
        var Animal = function(){}
        
        Animal.prototype = {
            sleep: function(){
                 console.log('zzz');   
            },
            bark: function(name){
                 console.log(name +' barks!');   
            }
        }
        
        var dog = new Animal();
        
        dog.sleep();
        dog.bark('asdasd');
        

        【讨论】:

        • var cat = new Animal(); cat.bark('a cat');。我认为 OP 知道他们想要在这里继承。
        【解决方案6】:
        var Animal = function(name){
            this.name = name;
        }
        Animal.prototype.sleep = function() {
            console.log("Sleeping")
        }
        
        ... 
        // Without this line:
        Dog.prototype = new Animal();
        
        // the following code will fail, since `d` does not contain `sleep`
        d = new Dog();
        d.sleep();
        

        Animal.call(this,name); 只是调用函数Animal,但使用与调用函数相同的this

        Dog.prototype = new Animal(); 设置原型的原型。但是,Dog.prototype = Object.create(Animal.prototype) 可能更正确。

        【讨论】:

        • 我不确定Dog.prototype = Object.create(),因为Object.create() 已经将新创建的对象的.prototype 设置为您传入的对象。
        • @jAndy:这不是重点吗?您希望Dog.prototype.__proto__ 成为Animal.prototype,以便继承成员,但您不希望Dog.prototype 成为Animal 的完整实例。
        • 注意,Object.create()not compatible with IE less than 9 和其他一些浏览器。
        猜你喜欢
        • 2013-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        • 2010-09-28
        • 2018-02-21
        相关资源
        最近更新 更多