简体   繁体   English

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

[英]Javascript inheritance: calling Object.create when setting a prototype

I'm learning some aspects of Object-oriented Javascript. 我正在学习面向对象的Javascript的一些方面。 I came across this snippet 我遇到了这个片段

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");

And my question is: why does this snippet use Object.create(Person.prototype)? 我的问题是:为什么这个代码片段使用Object.create(Person.prototype)? Shouldn't we simply reset prototype with: 我们不应该简单地重置原型:

Employee.prototype = Person.prototype;

Doing Employee.prototype = Person.prototype is like saying "Employee is Person" rather than "Employee is a Person." 做Employee.prototype = Person.prototype就像是说“员工就是人”而不是“员工就是一个人”。 Any changes to either prototype will be reflected in both classes. 对原型的任何更改都将反映在两个类中。

Here's a demonstration . 这是一个演示 Obviously we don't want our Persons working because they don't have a position. 显然,我们不希望我们的人员工作,因为他们没有职位。

So the right way to setup the prototype chain without Object.create is: 因此,在没有Object.create的情况下设置原型链的正确方法是:

Employee.prototype = new Person;

But this requires instantiating an object, which is a little funky -- especially if you don't want Person's constructor to be called. 但这需要实例化一个对象,这有点时髦 - 特别是如果你不想要调用Person的构造函数。 All of your Employee instances are going to inherit undefined "firstName" and "lastName" properties, regardless of whether you wanted that. 无论您是否想要这样,所有Employee实例都将继承未定义的“firstName”和“lastName”属性。

In this case it's no big deal -- the Employee constructor is going to set those properties on itself which will supersede the properties inherited from Person. 在这种情况下,它没什么大不了的 - Employee构造函数将自己设置这些属性,这将取代从Person继承的属性。 But consider this example . 但请考虑这个例子 One might think that freeTime is an instance level property for Person that will not be copied because it's not on the prototype. 有人可能会认为freeTime是Person的实例级属性,因为它不在原型上,所以不会被复制。 Plus, we never called the Person constructor from Employee. 另外,我们从未从Employee调用Person构造函数。 Not so -- freeTime was set on the Employee prototype because we had to instantiate an object. 不是这样 - 在Employee原型上设置了freeTime 因为我们必须实例化一个对象。

So the best and cleanest inheritance you can do is through Object.create. 所以你可以做的最好和最干净的继承是通过Object.create。 If you want to call the parent class' constructor, you can do so explicitly from within the subclass' constructor. 如果要调用父类的构造函数,可以在子类的构造函数中显式地执行此操作。 Another nice thing is that Object.create has a second (optional) argument to defineProperties. 另一个好处是Object.create有一个defineProperties的第二个(可选)参数。 So you can also do this: 所以你也可以这样做:

Employee.prototype = Object.create(Person.prototype, {
  work: {
    value: function() {
      return this.fullName+" is doing some "+this.position+" stuff");  
    }
  }
});

Of course, if you have to support legacy browsers you can't use Object.create. 当然,如果您必须支持旧版浏览器,则无法使用Object.create。 The alternative is to use clone / extend from libraries like underscore or lodash. 另一种方法是使用下划线或lodash等库中的clone / extend。 Or there's this little dance: 或者是这个小舞蹈:

var subclass = function() { };
subclass.prototype = Person.prototype;
Employee.prototype = new subclass;

My guess is that the intent is to create a new object rather than just a reference from Person. 我的猜测是意图是创建一个新对象而不仅仅是Person的引用。

//create a new object with its prototype assigned to Person.prototype
Employee.prototype = Object.create(Person.prototype);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM