Javascript 继承: 调用超级构造函数还是使用原型链?

最近我在 MDC 中读到了 JavaScript 调用的使用

Https://developer.mozilla.org/en/javascript/reference/global_objects/function/call

下面这个例子的一个链接,我还是不明白。

他们为什么要这样利用继承权

Prod_dept.prototype = new Product();

中的超级构造函数调用

Prod_dept()

不管怎样,像这样

Product.call

这只是不寻常的行为吗?何时使用调用超级构造函数或使用原型链更好?

function Product(name, value){
this.name = name;
if(value >= 1000)
this.value = 999;
else
this.value = value;
}


function Prod_dept(name, value, dept){
this.dept = dept;
Product.call(this, name, value);
}


Prod_dept.prototype = new Product();


// since 5 is less than 1000, value is set
cheese = new Prod_dept("feta", 5, "food");


// since 5000 is above 1000, value will be 999
car = new Prod_dept("honda", 5000, "auto");

谢谢你把事情说清楚

88357 次浏览

最理想的方法是 没有Prod_dept.prototype = new Product();,因为这会调用 Product构造函数。所以理想的方法是克隆它,除了构造函数,像这样:

function Product(...) {
...
}
var tmp = function(){};
tmp.prototype = Product.prototype;


function Prod_dept(...) {
Product.call(this, ...);
}
Prod_dept.prototype = new tmp();
Prod_dept.prototype.constructor = Prod_dept;

然后在构造时调用超级构造函数,这正是您想要的,因为这样您也可以传递参数。

如果你看看像 Google 闭包库这样的东西,你会发现他们就是这样做的。

真正问题的答案是,你需要两者兼顾:

  • 将原型设置为父类的实例将初始化原型链(继承) ,这只做一次(因为原型对象是共享的)。
  • 调用父构造函数初始化对象本身,每次实例化都是这样做的(每次构造时可以传递不同的参数)。

因此,在设置继承时不应调用父构造函数。只有在实例化从另一个对象继承的对象时。

Chris Morgan 的答案几乎是完整的,缺少一个小细节(构造函数属性)。

function extend(base, sub) {
// Avoid instantiating the base class just to setup inheritance
// Also, do a recursive merge of two prototypes, so we don't overwrite
// the existing prototype, but still maintain the inheritance chain
// Thanks to @ccnokes
var origProto = sub.prototype;
sub.prototype = Object.create(base.prototype);
for (var key in origProto)  {
sub.prototype[key] = origProto[key];
}
// The constructor property was set wrong, let's fix it
Object.defineProperty(sub.prototype, 'constructor', {
enumerable: false,
value: sub
});
}


// Let's try this
function Animal(name) {
this.name = name;
}


Animal.prototype = {
sayMyName: function() {
console.log(this.getWordsToSay() + " " + this.name);
},
getWordsToSay: function() {
// Abstract
}
}


function Dog(name) {
// Call the parent's constructor
Animal.call(this, name);
}


Dog.prototype = {
getWordsToSay: function(){
return "Ruff Ruff";
}
}


// Setup the prototype chain the right way
extend(Animal, Dog);


// Here is where the Dog (and Animal) constructors are called
var dog = new Dog("Lassie");
dog.sayMyName(); // Outputs Ruff Ruff Lassie
console.log(dog instanceof Animal); // true
console.log(dog.constructor); // Dog

在创建类的时候,请参考我的博客文章,了解更多的语法知识

从 Ext-JS 和 http://www.uselesspickles.com/class_library/复制的技术以及来自 https://stackoverflow.com/users/1397311/ccnokes的注释

如果你用 JavaScript 做过面向对象编程,你就会知道你可以创建一个类,如下所示:

Person = function(id, name, age){
this.id = id;
this.name = name;
this.age = age;
alert('A new person has been accepted');
}

到目前为止,我们的 class person 只有两个属性,我们将给它一些方法。干净利落的做法是 使用它的“原型”对象。 从 JavaScript 1.1开始,原型对象是在 JavaScript 中引入的 简化了向对象的所有实例添加自定义属性和方法的过程。 让我们使用它的“原型”对象向我们的类添加2个方法,如下所示:

Person.prototype = {
/** wake person up */
wake_up: function() {
alert('I am awake');
},


/** retrieve person's age */
get_age: function() {
return this.age;
}
}

现在我们已经定义了类 Person。如果我们想定义另一个名为 Manager 的类,它从 Person 继承一些属性,那么应该怎么做。在定义 Manager 类时,没有必要重新定义所有这些属性,我们只需将其设置为从 Person 类继承。 JavaScript 没有内置继承,但是我们可以使用以下技术来实现继承:

Inheritance_Manager = {};//我们创建一个继承管理器类(名称是任意的)

现在,让我们为继承类提供一个名为 tended 的方法,该方法接受 baseClass 和 subClassas 参数。 在扩展方法中,我们将创建一个名为继承函数继承(){}的内部类。我们使用这个内在的原因 类是为了避免 baseClass 和 subClass 原型之间的混淆。 接下来,我们让继承类的原型指向 baseClass 原型,如下面的代码所示: 原型 = baseClass 原型; 然后,我们将继承原型复制到子类原型中,如下所示: 下一步是为我们的 subClass 指定构造函数,如下所示: 完成 subClass 原型设计之后,我们可以指定接下来的两行代码来设置一些基类指针。

subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;

下面是扩展函数的完整代码:

Inheritance_Manager.extend = function(subClass, baseClass) {
function inheritance() { }
inheritance.prototype = baseClass.prototype;
subClass.prototype = new inheritance();
subClass.prototype.constructor = subClass;
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
}

现在我们已经实现了继承,我们可以开始使用它来扩展类。在这种情况下,我们将 将 Person 类扩展为 Manager 类,如下所示:

我们定义 Manager 类

Manager = function(id, name, age, salary) {
Person.baseConstructor.call(this, id, name, age);
this.salary = salary;
alert('A manager has been registered.');
}

我们让它从 Person 继承

Inheritance_Manager.extend(Manager, Person);

如果您注意到的话,我们刚刚调用了 Heritage _ Manager 类的扩展方法,并在本例中传递了子类管理器,然后传递了 baseClass Person。注意这里的顺序非常重要。如果你把它们交换,遗产 将不会按照你的意图工作,如果在所有。 还要注意,在实际定义我们的子类之前,您需要指定这个继承。 现在让我们定义我们的子类:

我们可以像下面这样添加更多的方法。我们的 Manager 类始终具有在 Person 类中定义的方法和属性,因为它是从它继承的。

Manager.prototype.lead = function(){
alert('I am a good leader');
}

现在为了测试它,让我们创建两个对象,一个来自类 Person,一个来自继承的类 Manager:

var p = new Person(1, 'Joe Tester', 26);
var pm = new Manager(1, 'Joe Tester', 26, '20.000');

欢迎在以下网址获得完整代码和更多注释: Http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx