实现原型继承的正确方法

时间:2015-05-23 10:41:03

标签: javascript oop inheritance prototype

JavaScript中有很多关于原型继承的线程,但由于懒惰,这不是副本。我已经完全阅读了所有内容,并且发现了几乎与我找到答案一样多的不同语法方法,所以看来我并不是唯一一个对此主题感到困惑的人!

具体细节:

我目前的做法是这样的。

var Person = function(name) {
    this.name = name;

    this.greeting = function() {
        alert("Greetings, I am " + name);
    }

}

var bob = new Person("bob");
bob.greeting();

var Woman = function(name) {
    Person.call(this, name);
    this.gender = "female";
}

Woman.prototype = Object.create(Person.prototype);

var brenda = new Woman("brenda");
brenda.greeting();

Person.prototype.eats = true;

alert(brenda.eats);

测试了代码后我发现它完美无缺 - 据我所知 - 但我被告知这不是最好的方法,我应该像这样定义构造函数:

Woman.prototype.constructor = Woman;

不要在我的实际构造方法中使用Person.call方法。有两件事,被告知我无法通过第二种方法看到一个简单的方法来传递参数,还有,为什么呢?我正在做的事似乎工作正常。

我错过了什么吗?

在某些情况下,我所做的事情会产生不可预测的错误吗?

任何人都可以给出明确的'正确的'方法及其原因?

2 个答案:

答案 0 :(得分:5)

我认为,你所拥有的是最好的方法。你提出的观点是无关紧要的:

Woman.prototype.constructor = Woman;

不是Person.call(...)的替代品。事实上,这两件事没有任何共同之处,它们有不同的用途:

  • 在子构造函数中调用父构造函数可确保正确初始化子实例。这就像在ES6或其他语言中调用super()

  • 分配到constructor只会恢复Women.prototype.constructor的原始值。如果您不这样做,brenda.constructor会引用Person。这不会对继承的内部工作产生影响,但使用对象的其他代码可能依赖于具有正确值的constructor。另请参阅Advantages of setting the "constructor" Property in the "prototype"

所以问题的答案是:你应该同时做到这两点。

有时您会看到作业是Object.create来电的一部分。这更加准确,因为它重新创建了属性的原始特征(如非可枚举性):

Woman.prototype = Object.create(Person.prototype, {
  constructor: {value: Woman, writable: true}
});

FWIW,我相信在ES6中引入class的原因之一是减少构造函数和原型的混淆。这并不是说你不应该知道它,毕竟,class或多或少只是语法糖,但它只是让继承更容易:

class Woman extends Person { // almost like Woman.prototype = Object.create(Person.prototype)
  constructor(name) {
    super(name); // almost like Person.call, but enforced by the interpreter
    this.gender = "female";
  }
}

答案 1 :(得分:0)

这是JS中的OOP方法

var Person = function(name) {
    this.name = name;
}

Person.prototype.greeting = function(){ 
    var newPerson = new Person(this.name);
    alert("Greetings, I am " + name);
    return newPerson;
} 

Person.prototype.toString=function(){ 
    return '[Person "'+this.name+'"]';
} 

Woman.prototype = new Person();

Woman.prototype.constructor=Woman;      

function Woman(name){ 
    this.name=name;
} 

Woman.prototype.toString=function(){ 
    return '[Woman "'+this.name+'"]';
} 

var somePerson = new Person('Mr.');
var myPerson = new Woman('She');
alert('somePerson is '+somePerson);   // results in 'somePerson is [Person "Mr."]' 
alert('myPerson is '+myPerson);             // results in 'myPerson is [Woman "She"]' 

myPerson.greeting();                    // calls a method inherited from Person