简体   繁体   English

了解Javascript原型继承

[英]Understanding Javascript prototypical inheritance

I am afraid to ask this question, as already there are so many on the same topic. 恐怕要问这个问题,因为在同一主题上已经有很多这样的问题。

I am trying to understand cons/limitations of using approach-1 and approach-2 我试图了解使用approach-1approach-2缺点/局限性

Simple Inheritance 简单继承

 function Person(name, age) { this.name = name || "de-name"; this.age = !!Number(age) ? Number(age) : 0; } Person.prototype.setName = function(name) { this.name = name; return this; } function Student(name) { Person.call(this, name); // Copy instance properties of Person class this.title = "Student"; } // Suggested way Student.prototype = Object.create(Person.prototype); // Possible approach-1 // Student.prototype = Person.prototype; // Possible approach-2 // Student.prototype = new Person(); 

In prototype-based languages, inheritance is performed by cloning existing objects that serve as prototypes rather than having classes. 在基于原型的语言中,继承是通过克隆用作原型而不是具有类的现有对象来执行的。

So in each case, we should think about the object selected to use as the prototype to figure out the behavior. 因此,在每种情况下,我们都应该考虑选择用作原型的对象以确定行为的方式。

In approach 1, you're setting the prototype of Student to the same prototype object as Person . 在方法1中,您将Student的原型设置为与Person相同的原型对象。 This means that any changes made to Student.prototype will affect Person.prototype and vice versa. 这意味着对Student.prototype所做的任何更改都会影响Person.prototype ,反之亦然。

In approach 2, you're setting the prototype of Student to a new Person object that will have the following properties set {name: 'de-name', age: 0} according to your initialization code. 在方法2中,您将Student的原型设置为一个新的Person对象,该对象将根据您的初始化代码将以下属性设置为{name: 'de-name', age: 0} The name property will then be overriden by your call to Person.call() in the Student function. 然后,您在Student函数中对Person.call()调用将覆盖name属性。 Since this an entirely new object, any modifications to Student.prototype will only affect new Student objects, and any missing properties on this Person instance that serves as the prototype will be delegated to the Person.prototype . 由于这是一个全新的对象,因此对Student.prototype任何修改将仅影响新的Student对象,并且此Person实例上作为原型的任何缺少的属性都将委派给Person.prototype

To elaborate on that last bit (that missing properties are passed up the prototype chain), here's an example. 为了详细说明最后一点(缺少的属性在原型链中传递),下面是一个示例。 Say we add a new method greet to Person : 假设我们添加一个新的方法greetPerson

Person.prototype.greet = function() { console.log("Hi! " + this.name; ) }

Calling new Student().greet() will have JavaScript check through the prototype chain until it hits the appropriate property (otherwise you get a not defined error.) 调用new Student().greet()将使JavaScript在原型链中进行检查,直到遇到适当的属性为止(否则,您将得到未定义的错误。)

// Walking up the chain
/* 1 */ new Student()     // doesn't have a greet property
/* 2 */ Student.prototype // => Person {name: 'de-name', age: 0}
// This person instance doesn't have a greet property either
// because we instantiated it before adding the `greet` property
/* 3 */ Person.prototype  // Has a greet property which gets called

In the suggested pattern with Object.create , you're doing almost the same thing as Student.prototype = new Person() except that Object.create allows you to perform differential inheritance . Object.create的建议模式中,您执行的操作与Student.prototype = new Person()几乎相同,只是Object.create允许您执行差异继承 You can even add additional properties as its second argument: 您甚至可以添加其他属性作为其第二个参数:

Student.prototype = Object.create(Person.prototype, {
  age: 16,
  study: function() { console.log("But I'm sooo lazy!!!"); } 
});

Approach 1 and Approach 2 are actually not the same, exactly. 实际上,方法1和方法2并不完全相同。 In approach 2, you're creating a new instance of Person , and assigning that new instance to the prototype of Student. 在方法2中,您将创建一个Person的新实例,并将该新实例分配给Student的原型。

Additionally, you're supposed to do it this way: 此外,您应该这样做:

var Student = Object.create(Person.prototype);

According to MDN : 根据MDN

The Object.create() method creates a new object with the specified prototype object and properties.

So you don't assign it to the Student prototype, you assign it to the Student itself, and Student gets Person as its prototype. 因此,您无需将其分配给Student原型,而是将其分配给Student本身,然后Student获得Person作为其原型。

approach-2 means one additional object in the prototype chain. Approach-2表示原型链中的另一个对象。 If (new Student()).someAttr doesn't resolve in the student object ( new Student() ), with approach-2, the person object ( new Person() ) is checked (because that's what's in Student.prototype ), then Person.prototype . 如果(new Student()).someAttr没有在学生对象( new Student() )中解析,则采用方法2,将检查人员对象( new Person() )(因为这是Student.prototype ),然后Person.prototype With approach-1, there's no person object. 使用方法1时,没有人对象。

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

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