Javascript继承:在设置原型时调用Object.create

8

我正在学习面向对象的JavaScript。我发现了这个代码片段:

var Person = function(firstName, lastName)
{
  this.lastName = lastName;
  this.firstName = firstName;
};

Object.defineProperties(Person.prototype, {
  sayHi: {
    value: function() {
      return "Hi my name is " + this.firstName;
    }
  },
  fullName: {
    get: function() {
      return this.firstName + " " + this.lastName;
    }
  }
});

var Employee = function(firstName, lastName, position) {
  Person.call(this, firstName, lastName);
  this.position = position;
};

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

var john = new Employee("John", "Doe", "Dev");

我有一个问题:为什么这个片段使用Object.create(Person.prototype)?我们不应该只是重置原型吗?
Employee.prototype = Person.prototype;

2
今天针对这个问题的一个很棒的答案。 - marekful
哇,谢谢你。收藏起来以备学习! :-) - james emanon
No. - Bergi
2个回答

9

将Employee.prototype设置为Person.prototype就相当于说“Employee是Person”,而不是“Employee是一个Person”。对任一原型的更改都将反映在 两个 类中。

这里有一个演示。显然,我们不希望我们的Person工作,因为他们没有职位。

因此,正确的设置原型链的方法不需要使用Object.create:

Employee.prototype = new Person;

但是这需要实例化一个对象,这有点奇怪 - 特别是如果您不想调用Person的构造函数。无论您是否希望如此,所有Employee实例都将继承未定义的“firstName”和“lastName”属性。
在这种情况下,这没什么大不了的 - Employee构造函数将在其自身上设置这些属性,这将取代从Person继承的属性。但考虑一下此示例。人们可能认为freeTime是Person的实例级属性,因为它不在原型上,所以不会被复制。此外,我们从未从Employee调用Person构造函数。但并非如此 - freeTime在Employee原型上被设置,因为我们必须实例化一个对象。
因此,您可以通过Object.create进行最佳和最清洁的继承。如果您想调用父类的构造函数,则可以在子类的构造函数中显式地这样做。另一个好处是,Object.create有第二个(可选)参数来定义属性。因此,您还可以这样做:
Employee.prototype = Object.create(Person.prototype, {
  work: {
    value: function() {
      return this.fullName+" is doing some "+this.position+" stuff");  
    }
  }
});

当然,如果你必须支持旧版浏览器,就不能使用Object.create。另一种选择是使用类似underscore或lodash的库中的clone/extend方法。或者可以尝试以下步骤:
var subclass = function() { };
subclass.prototype = Person.prototype;
Employee.prototype = new subclass;

为什么这是正确的方式?我的意思是,如果Person对象有属性/字段(firstName,lastName),那么Employee的原型应该可以访问它们吗?而且我需要提供lastName和firstName,因为构造函数需要它们。 - dragonfly
更新了演示。 - Andrew Kirkegaard
我认为这里给出的例子很糟糕。我本来期望freeTime会被复制到子对象中,因为它是在父类的构造函数中设置的,而你应该从子类的构造函数中调用该构造函数。 - Jez

1
我猜测意图是创建一个新对象而不仅仅是从Person中引用。
//create a new object with its prototype assigned to Person.prototype
Employee.prototype = Object.create(Person.prototype);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接