2011-11-28 74 views
1

我在玩JavaScript类继承(我使用node.js)。我得到了子类的实例的“未定义”值。这里我的例子:如何专门化Javascript类?

我定义了一个Squirrel类,我想在KillerSquirrel子类中专门化这个类。我想创建Squirrel和KillerSquirrel类的实例。

function Squirrel(name, color) { 
     this.name = name; 
     this.color = color; 
     console.log("A new " + this.color + " squirrel named " + this.name + " is born!!!"); 
    }; 

    // add a new method called speak() 
    Squirrel.prototype.speak = function(text) { 
     console.log(this.name + " squirrel says: '" + text + "'"); 
    }; 

    // specialize the Squirrel class by creating a new KillerSquirrel constructor 
    function KillerSquirrel(name, color) {  
     this.soul = 'very bad'; 
     console.log("Bhrrr ... a new " + this.color + " killer squirrel named " + this.name + " is born!!!"); 
    } 
    KillerSquirrel.prototype.__proto__ = Squirrel.prototype; 

    // add kill method 
    KillerSquirrel.prototype.kill = function(obj){ 
     console.log(this.name + " squirrel killed " + obj.name + " squirrel"); 
    } 

    // replace the speak() method 
    KillerSquirrel.prototype.speak = function(text) { 
         console.log(this.name + " squirrel says: 'Grhhh! " + text + "' Grhhh!"); 
    }; 

    var squirrel = new Squirrel("Gummy", "brown"); 
    squirrel.speak("My name is " + squirrel.name); 
    var killer = new KillerSquirrel("Mr.Hide", "black"); 
    killer.speak("My name is " + killer.name); 

我使用它的构造函数创建松鼠的松鼠实例,并将一些值传递给构造函数,并按预期工作。当我尝试使用它的构造函数创建一个KillerSquirrel类的实例并传递一些值时,杀手松鼠实例具有“未定义的属性”。

看到:(申请或电话)

$ node killersquirrel.js 
A new brown squirrel named Gummy is born!!! 
Gummy squirrel says: 'My name is Gummy' 
Bhrrr ... a new undefined killer squirrel named undefined is born!!! 
undefined squirrel says: 'Grhhh! My name is undefined' Grhhh! 
+0

_all_松鼠是杀手松鼠 - 没有必要继承它们! ;-) – Alnitak

+0

不确定要理解评论。谢谢 – kalise

+0

@kalise我认为评论是一个笑话。 –

回答

4

子类的构造应该调用父类的构造特殊结构手动,像这样:

function KillerSquirrel(name, color) { 
    Squirrel.apply(this, arguments);  
    this.soul = 'very bad'; 
    console.log("Bhrrr ... a new " + this.color + " killer squirrel named " + this.name + " is born!!!"); 
} 

function KillerSquirrel(name, color) { 
    Squirrel.call(this, name, color);  
    this.soul = 'very bad'; 
    console.log("Bhrrr ... a new " + this.color + " killer squirrel named " + this.name + " is born!!!"); 
} 

虽然此情况下(当参数相同时)第一种形式是优选的。

+0

谢谢!有用。你能否详细解释一下apply()和call()函数的作用?和哪个不同? – kalise

+0

阅读EcmaScript规范;-)这不是一个简单的阅读,但你至少得到2级(并深入了解它)。但是很快回答 - “call”和“apply”允许你像调用方法一样“调用”任何函数,唯一的区别在于参数。给定函数f,'f.apply(foo,[99,“bottles”])'和f.call(foo,99,“bottles”)相同,都是'foo._tmp_method_ = f; var _result_ = foo._tmp_method_(99,“bottles”);删除foo._tmp_method_; return _result_;'但实际上没有使用任何'_tmp_method_'。也就是说,第一个参数被用作'this'。 – 2011-11-28 13:03:27

+0

最后一块拼图是'arguments'(它是一个特殊的名字,而不是一个普通的变量),它包含所有传递给函数的参数(因此你可以在'apply'中调用它)。 – 2011-11-28 13:05:49