通过.prototype添加到对象的方法是不是被继承?

时间:2015-09-25 12:42:50

标签: javascript inheritance methods

我是Javascript的新手,这是关于继承的基本问题。

在我正在查看的网站中,向对象的原型添加新方法看起来非常简单。以下是他们展示的方法:

function Gadget(name, color) { 
   this.name = name; 
   this.color = color; 
}

Gadget.prototype.getInfo = function() { 
   return 'Rating: ' + this.rating + ', price: ' + this.price;
};

然而,尝试复制同样的事情,我收到一个错误:

(function() {

    window.onload = function() {
        document.getElementById("main").innerHTML = getMessage();
    }

    function Animal(){
        this.speak = function(){
            return "I am a " + this.species + ", hear me " + this.sound + "!";
        }
    }

    function Cat(){
        this.__proto__ = new Animal();
        this.species = "cat";
        this.sound = "meow";
    }

    function getMessage(){
        var cat = new Cat();
        Cat.prototype.pounce = function() { return "Pounce!"};    //Adding prototype function here

        var Boots = {};
        Boots.__proto__ = new Cat();

        return cat.speak() + '<br>' + Boots.pounce();   //Returning message that Boots.pounce() doesn't exist
    }

})()

当我在调试窗口中查看Cat()对象时,它向我显示它没有属性“pounce”,Boots也没有。我在这做什么不起作用?

我认为自从我将该函数添加到对象的原型后,它将被添加到原型链中,从而继承。

非常感谢你的时间。

2 个答案:

答案 0 :(得分:1)

__proto__的行为从未标准化,只有legacy feature除外。

如果您使用Object.create方法,则会有更好的时间。它将原型作为第一个参数,并返回一个使用该原型的对象。

如果使用Object.create重写您的代码可能看起来更像这样。

function Animal() {

}

// you don't need to this, but it shows the prototype chain explicitly
Animal.prototype = Object.create(Object.prototype);

Animal.prototype.speak = function() {
  return "I am a " + this.species + ", hear me " + this.sound + "!";
};

function Cat(){
  this.species = 'cat';
  this.sound = 'meow';
}

Cat.prototype = Object.create(Animal.prototype);

Cat.prototype.pounce = function() {
  return "Pounce";
};

function getMessage() {
  var cat = new Cat();

  // you could dynamically add methods to the prototype, but the
  // code will be faster if you declare the properties on the
  // prototype, as early as possible

  var Boots = new Cat();
  return cat.speak() + '<br>' + Boots.pounce();
}

答案 1 :(得分:1)

这不是你如何使用原型,所以让我们以更标准化的方式重建它:

function Animal(){
    this.species = 'Undefined';
    this.sound = 'silence';
}

Animal.prototype = {
    speak: function(){
        return "I am a " + this.species + ", hear me " + this.sound + "!";
    }
}

function Cat(){
    Animal.apply(this);
    this.species = 'cat';
    this.sound = 'miauw';
}

Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.pounce = function(){ return 'Pounce!'; }

那我们在这做了什么?我们首先创建一个function,这通常被称为我们的构造函数。它主要用于设置存储的参数。然后我们创建一个原型object,其中包含prototype的方法(以及可能的原型参数)。

要创建Cat,我们创建另一个函数,然后将第一个function应用于当前this对象。这允许您继承原始构造函数在运行时所执行的所有操作。它基本上运行Animal的设置,但在我们的新Cat上。然后你做自定义的事情,比如将物种设置为'猫'。之后,我们将复制预先存在的Animal原型,然后向其添加更多方法。

需要注意的是,所有这些都会进入prototype密钥,不会 __proto__。以双下划线开头的键和变量是你永远不应该触摸的东西,几乎从不使用它们 - 它们被认为是系统为你做的事情。您之前看到的__proto__是以编程方式应用prototype的结果,您可以在控制台中看到它,但它不是您应该搞的东西。

现在我们可以这样做:

// Ignore this bit, it's a repeat of the code above 
// so I condensed it to a single line. Otherwise, exactly the same.
function Animal(){ this.species = 'Undefined'; this.sound = 'silence';}Animal.prototype = {speak: function(){return "I am a " + this.species + ", hear me " + this.sound + "!";}}; function Cat(){Animal.apply(this);this.species = 'cat';this.sound = 'miauw';}Cat.prototype = Object.create(Animal.prototype);Cat.prototype.pounce = function(){ return 'Pounce!'; }

// Helper function so the code reads clearly, 
// but also writes to the snippet and adds the linebreaks
// and strong tags where necessary
function w(m,s){document.write((s?'<strong>':'')+(m?m:'')+(s?'</strong>':'')+'<br />');};

// Create our variables with the animal and the cat
var justAnAnimal = new Animal();
var pussInBoots = new Cat();

w( 'Speaking', true ); w();
w( 'justAnAnimal.speak()', true );
w( justAnAnimal.speak() );
w( 'pussInBoots.speak()', true );
w( pussInBoots.speak() );

w(); w('Pouncing', true); w();
w( 'justAnAnimal.pounce()', true );
// Use variable.method to check if the method exist
// if it does, then execute it and write that with variable.method()
// Otherwise print a different message so we know whats going on.
w( 
  (justAnAnimal.pounce && justAnAnimal.pounce()) 
  || 'Not every animal pounces (method does not exist for this instance)!' 
);
w( 'pussInBoots.pounce()', true );
w( 
  (pussInBoots.pounce && pussInBoots.pounce()) 
  || 'Not every animal pounces (method does not exist for this instance)!' 
);

w(); w('Checking the type of your animals using instanceof', true); w();
w( 'is justAnAnimal an Animal?', true );
w( justAnAnimal instanceof Animal ? 'Yes' : 'No' );
w( 'is justAnAnimal a Cat?', true );
w( justAnAnimal instanceof Cat ? 'Yes' : 'No' );
w( 'is pussInBoots an Animal?', true );
w( pussInBoots instanceof Animal ? 'Yes' : 'No' );
w( 'is pussInBoots a Cat?', true );
w( pussInBoots instanceof Cat ? 'Yes' : 'No' );
body {
  font-family: 'Monaco', 'Courier MS', courier, monospace;
  font-size: 10px;
}
strong {
  color: #777;
  margin-right: 20px;
  display: inline-block;
  font-weight: normal;
}

我发现这使得您的代码看起来更干净,因为一切都非常简单。构造函数,原型,一切都落入一个易于区分的模式,并且清晰可读。

在MDN上发表了一篇全面的文章:https://developer.mozilla.org/en/docs/Web/JavaScript/Inheritance_and_the_prototype_chain