我正在努力理解Javascript中的构造函数调用模式。
我有一个基础对象Mammal
(使用术语 class ?)和继承的对象Cat
是不正确的。在以下代码中,对象Cat
正确地从Mammal对象继承。
/*
Mammal base Object
*/
var Mammal = function(name) {
this.name = name;
}
Mammal.prototype.get_name = function() {
return this.name;
}
Mammal.prototype.says = function () {
return this.saying || '';
}
/*
Cat object
*/
var Cat = function (name) {
this.saying = "Meow";
this.name = name;
}
Cat.prototype.purr = function (number) {
var i =0, s='';
for ( i=0; i<number; i++)
if (s)
s +='-';
s+='r';
return s;
}
Cat.prototype = new Mammal();
console.log("Pseudo classical inheritance approach");
var mammal = new Mammal(" I am a mammal");
console.log("Who are you ? " + mammal.get_name());
console.log("What are you saying? " + mammal.says());
var cat = new Cat('I am a cat');
console.log("Who are you ? " + cat.get_name());
console.log("What are you saying? " + cat.says());
我在这种模式中不喜欢的是如何使用基础对象的构造函数。对象Cat
未正确重用基类Mammal
的构造函数。我想有更多的灵活性。每次创建Cat
对象时,都会调用Mammal
对象的构造函数而不带参数。我想在Java中使用类似于“super”关键字的机制,以便在使用Cat
作为参数调用name
的构造函数时,也会调用Mammal
的构造函数以name
作为参数。
我尝试按如下方式实现Cat
构造函数:
var Cat = function (name) {
this.saying = "Meow";
// Super (name);
this.prototype = new Mammal(name);
}
这不能按预期工作。 this.prototype
未定义。为什么?为什么这种方法完全错误? this
是否指向新Cat
对象?
我知道,在javaScript中有不同的方法来实现继承,但我想知道是否有一种方法可以像Java一样实现超级机制。
感谢。 :D
答案 0 :(得分:2)
怎么样
var Cat = function (name) {
this.saying = "Meow";
// Super (name);
Mammal.call( this, name );
}
答案 1 :(得分:1)
是的,我担心这不是你设置层次结构的方式。它很接近,但有一些关键问题。 (其中一个 - 调用new Mammal()
来创建Cat.prototype
- 是一个非常,非常非常频繁的错误,你会在很多博客文章等中看到。)
以下是正确执行此操作的简单示例:
// A function to set up the link between a child and parent
function derive(Child, Parent) {
// `ctor` is a temporary function we use so we can get an object
// backed by `Parent.prototype` but without calling `Parent`.
function ctor() { }
// Borrow the prototype
ctor.prototype = Parent.prototype;
// Create an object backed by `Parent.prototype` and use it as
// `Child`'s prototype
Child.prototype = new ctor();
// Some housekeeping to make the prototype look like the ones
// the JavaScript engine creates normally.
Child.prototype.constructor = Child;
// Note: If we can rely on ES5 features, we could use
// `Object.create` instead of the `ctor` function.
}
// The parent constructor
var Mammal = function(name) {
this.name = name;
};
// Some stuff for its prototype
Mammal.prototype.get_name = function() {
return this.name;
};
Mammal.prototype.says = function () {
return this.saying || '';
};
// The child constructor
var Cat = function(name) {
Mammal.call(this, name);
this.saying = "Meow";
};
// Hook it up to the parent
derive(Cat, Mammal);
// Add some things to its prototype
Cat.prototype.purr = function (number) {
var i =0, s='';
for ( i=0; i<number; i++)
if (s)
s +='-';
s+='r';
return s;
};
如果您对使用JavaScript进行继承层次结构感兴趣,可能会发现我的Lineage
script很有用。您可能会也可能不会选择使用它,但它演示了如何设置,调用父版本的方法(“超级调用”)等等。特别是this documentation page使用{{进行比较1}}不使用它显示如何在没有任何帮助脚本的情况下执行此操作。但是有一个原因我写了一个帮助脚本来做它。 : - )
答案 2 :(得分:1)
this.prototype
未定义,因为没有人定义它。
Cat
是一个功能。因此,它具有属性prototype
。这是ECMAScript标准规定的。
this
是一个不是函数的对象。因此,ECMAScript标准并未强制要求它具有prototype
属性。
如果this
是Cat
(即使用new Cat
创建或创建的对象),则为了规范,,内部[[Prototype]]
属性,Mamal
。但是这个mamal不能直接访问(正如 internal 这个词所暗示的那样)。当您说var maru = new Cat()
时,maru.[[Prototype]]
与Cat.prototype
相关联。这就是maru
对未来mamals方法的了解。