2015-09-25 68 views
0

我是Javascript的总新手,这是一个关于继承的基本问题。通过.prototype向对象添加的方法没有被继承?

在我看到的网站中,向对象原型添加新方法看起来非常简单。下面是该方法显示,他们是:

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 
    } 

})() 

当我看到猫()对象在调试窗口,它显示我没有财产“突袭”,靴子也没有。我在这里做什么不起作用?

我会认为,因为我将函数添加到对象的原型,它将被添加到原型链,因此被继承。

非常感谢您的时间。

+2

这不是你如何使用原型! 'this .__ proto__ = new Animal()'是错误的!使用'Cat.prototype = Object.create(Animal.prototype)'和'Animal.apply(this)'来正确地创建一个继承。 – somethinghere

+0

现在我更加困惑。你能举个例子吗? – SemperCallide

+0

正在工作!这似乎是一个很好的尝试,但是误导了:) – somethinghere

回答

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

这不是你如何使用原型,所以让我们重建它在一个更加规范的方式:

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原有原型的,然后在其中添加更多方法。

重要的是要注意的是,所有这一切进入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