js inheritance borrowing constructor inheritance

from:http://www.cnblogs.com/sarahwang/p/6879161.html

My last article introduced the prototype chain inheritance pattern . But the pure prototype chain pattern does not implement inheritance very well.

1. Disadvantages of Prototype Chain

1.1 The biggest disadvantage of pure prototype chain inheritance comes from the fact that the prototype contains the value of the reference type.

Originally, before we implemented inheritance through the prototype chain, all instances of the subclass shared all the properties and methods on the prototype. Properties on the prototype can be accessed through subclass instances, however, properties on the prototype cannot be overridden.

copy code
//define a student class
function Student(stuID, schoolName) {
    this.stuID = stuID;
    this.schoolName = schoolName;
}
//All students have such a feature
Student.prototype.characteristic = 'Young and energetic';
            
var stu1 = new Student(1001,'First Primary School');
console.log(stu1.stuID);                //1001
console.log(stu1.characteristic); //'Young and energetic'
            
//Rewrite characteristic
stu1.characteristic = 'Lively and cute' ;
console.log(stu1.characteristic); //'Lively and cute'

var stu2 = new Student(1002,'First Primary School');
console.log(stu2.characteristic);        //'Young and energetic' 
console.log(Student.prototype); //{characteristic: "Young and energetic"}
copy code

  In the above code, the stu1 instance can access the attribute characteristic on the prototype, which prints "young and energetic"; then, we set stu1.characteristic = 'lively and lovely', then printing stu1.characteristic becomes "" energetic and cute". Does that mean that the characteristic attribute value on the prototype has been rewritten by us through the instance stu1? not at all. We found that the value of accessing stu2.characteristic is still "young and energetic". So the property value on the prototype will not be overridden by the instance.

  When there is a property with the same name as the prototype in the instance, the property with the same name on the prototype will be automatically blocked. stu1.characteristic = = 'lively and cute' actually adds a local attribute characteristic to the instance stu1, so when we visit stu1.characteristic again, we access the local attribute of the instance, not the characteristic attribute on the prototype (it is due to The same name as the local property name has been blocked).

  The characteristic value on the prototype is a value of a primitive type, what if it is a reference type? There will be a bunch of small nine-nine among them.

  In fact, any type of value on the prototype will not be overridden by the instance. Setting the value of a property on the instance with the same name as the prototype will only create a local property on the instance with the same name. However, the value of the reference type on the prototype can be modified by the instance, and the value of the reference type accessed by all instances will also change accordingly.

copy code
//define a student class
function Student(stuID, schoolName) {
    this.stuID = stuID;
    this.schoolName = schoolName;
}
//All students have such a feature
Student.prototype.characteristic = 'Young and energetic';
Student.prototype.examItems = ['Chinese','Math','English'];   //Exam items


var stu1 = new Student(1001, 'First Primary School');
console.log(stu1.examItems); //['Chinese','Math','English']

//Modify examItems
stu1.examItems.push('Science' );
console.log(stu1.examItems); //['Chinese','Math','English','Science']

var stu2 = new Student(1002, 'First Primary School');
console.log(stu2.examItems); //['Chinese','Math','English','Science']
copy code

  We added an exam item attribute examItems to the Student prototype just now, which is a reference type value. When the first instance stu1 accesses examItems, it gets ['Chinese', 'Math', 'English'], and then we add a "science" item to the array of examItems through stu1.examItems.push('Science'), When printed again, the array becomes ['Chinese','Math','English','Science']. The scary thing is that after that, the print instance stu2.examItems also becomes ['language','math','English','science'].

  Therefore, we conclude that property values ​​of any type on the prototype are not overridden by the instance, but property values ​​of reference types are modified by the influence of the instance.

1.2  The prototype chain cannot implement the transfer of parameters from subclasses to parent classes. I won't go into details here.

 

Second, borrow the constructor

2.1 Implementation principle

The implementation principle is that in the constructor of the subclass, the constructor of the parent class is called in the form of apply( ) or call( ) to achieve inheritance.

copy code
//Define a superclass/parent class: person
function Person (name, age) {
    //Everyone has a name, age, can eat, can sleep
    / / Pass in the year of birth year, automatically calculate the age
    this.name = name;
    this.age = age;
    this.eat = function () {
        alert('eat');
    }
    this.sleep = function () {
        alert('sleep');
    }
}

//Define a subclass: Student
//Student is also a human being, and naturally inherits all the properties and methods of the superclass Person
//Students should have name, age, can eat, can sleep
//Of course, students also have some attributes of their own: student number, school name, etc., and methods, such as doing one thing: writing homework
function Student (stuID, schoolName, name, age) {
    this.stuID = stuID;
    this.schoolName = schoolName;
    //Call Person with call to implement inheritance
    Person.call(this, name, age);
}

Student.prototype.doHomework = function () {
    alert('do homework');
}

//Instantiate a student
var stu1 = new Student(1001, 'First Primary School', 'Wang Baobao', 20);
console.log(stu1.stuID);       //1001
console.log(stu1.schoolName); //'First Primary School'
console.log(stu1.name); //'Baby Wang'
console.log(stu1.age);         //20
stu1.eat(); //'Eat'
stu1.sleep(); //'Sleep'
stu1.doHomework(); //'do homework'    
copy code

  The above code defines a parent class function Person and a subclass function Student. In the subclass constructor, we call the parent class constructor Person by calling to implement inheritance. Don't forget, a function is just a special object that can execute code in a specific scope, we can specify the scope of my function through the call method.

  When stu1 = new Student() constructor, the value of this inside Student points to stu1, so  this .stuID = stu1 .stuID, so Person.call( this , name, age) is equivalent to Person.call( stu1 , 'Baby Wang', 20) is equivalent to stu1.Person('Baby Wang', 20). Finally, when stu1 calls the Person method, the this inside Person points to stu1. Then all the properties and methods on this inside Person are copied to stu1. Speaking of which, everyone should be a little clearer.

  In short, in the subclass function, after calling the parent class function through the call() method, the subclass instance stu1 can access all the properties and methods in the Student constructor and the Person constructor. In this way, the inheritance of the subclass to the superclass is realized.

 

2.2 Disadvantages

  In this form of inheritance, each subclass instance will copy a method in the parent class constructor as the instance's own method, such as eat(). In doing so, there are several disadvantages:

  1. Each instance is copied, which takes up a lot of memory, especially when there are too many methods.

  2. The methods are used as the method of the instance itself. When the requirements change and one of the methods needs to be changed, all the previous instances cannot update the method in time. Only later instances can access the new method.

copy code
//Define a superclass/parent class: person
function Person (name, age) {
    //Everyone has a name, age, can eat, can sleep
    / / Pass in the year of birth year, automatically calculate the age
    this.name = name;
    this.age = age;
    this.eat = function () {
        alert('eat');
    }
    this.sleep = function () {
        alert('sleep' );
    }
}
copy code

 

  Therefore, in fact, using prototype chain inheritance alone or borrowing constructor inheritance has its own great disadvantages. The best way is to use the two together to give full play to their respective advantages . I will explain in the next article.

The content of the article is all referenced to "JAVASCRIPT Advanced Programming")

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324647595&siteId=291194637