Interviewer: How does JavaScript implement inheritance?

Table of contents

1. What is inheritance?

Two ways of inheritance

1. Prototype chain inheritance

2. Constructor inheritance

3. Composition inheritance

4. Prototype inheritance

5. Parasitic inheritance

6. Parasitic compositional inheritance

 3. Summary


1. What is inheritance?

Inheritance is a concept in object-oriented software technology.

If a class B "inherits" from another class A, this B is called a "subclass of A", and A is called a "parent class of B" or "A is a superclass of B"

Advantages of inheritance:

1. Inheritance allows subclasses to have various properties and methods of the parent class without having to write the same code again

2. While the subcategory inherits the parent category, it can redefine some attributes and rewrite some methods, that is, overwrite the original attributes and methods of the parent category, so that it can obtain different functions from the parent category

Regarding inheritance, you can give a vivid example first

The car class is the parent class, and trucks and cars are the subclasses that inherit some properties and methods of the car class. They can also rewrite the properties and methods of the parent class, and can also add some unique properties and methods of their own.

            // 汽车父类
            class Car {
                constructor(color, type) {
                    this.color = color;
                    this.type = type;
                }
                getColor() {
                    return this.color;
                }
            }
            // 货车子类
            class Truck extends Car {
                constructor(color, speed, container) {
                    super(color, name);
                    this.container = container;
                }
                getColor() {
                    return `货车的颜色为` + super.getColor();
                }
            }
            // Suv子类
            class Suv extends Car {
                constructor(color, speed, quick) {
                    super(color, name);
                    this.quick = quick;
                }
                getColor() {
                    return `Suv的颜色为` + super.getColor();
                }
            }
            let truck1 = new Truck('red', 200, 300);
            console.log(truck1.getColor()); // 货车的颜色为red
            let suv1 = new Suv('green', 200, 300);
            console.log(suv1.getColor()); // Suv的颜色为red

From this example, the inheritance relationship between cars, trucks and suvs can be explained in detail

Two ways of inheritance

1. Prototype chain inheritance

     Prototype chain inheritance is one of the more common inheritance methods. There is a certain relationship among the constructors, prototypes and instances involved, that is, each constructor has a prototype object, and the prototype object contains a pointer to the constructor A pointer to a function, while an instance contains a pointer to a prototype object

            function Parent() {
                this.name = 'parent';
                this.friends = ['zs', 'lisi', 'wangwu '];
            }
            function Child() {
                this.type = 'child';
            }
            Child.prototype = new Parent();
            let child1 = new Child();
            let child2 = new Child();
            child1.friends.push('sunqi');
            console.log(child1.friends, child2.friends);
            console.log(child1.__proto__);

The following figure is the prototype relationship diagram of the above example. We can know that Child.prototype executes the parent instance object parent1. When changing the value of the friends of the child1 object, the child1 instance object itself does not have this attribute, so it will search upwards and find the parent1 instance object, while child1 and child2 point to the same parent1 instance object , the memory space is shared

When the push value is added to parent1.friends, the value on the public prototype object parent1 is directly modified.

 The printout is as follows

2. Constructor inheritance

Borrowing call to call the Parent function , just calling the Parent's constructor to construct the object, does not realize the real prototype inheritance, only constructs the properties and methods of the Parent instance, and cannot access the properties and methods on the prototype

The reference properties of the parent class will not be shared, which optimizes the disadvantages of the first inheritance method , but can only inherit the instance properties and methods of the parent class, and cannot inherit prototype properties or methods

        <script>
            function Parent() {
                this.name = 'parent';
            }
            Parent.prototype.getName = function () {
                return this.name;
            };
            function Child() {
                Parent.call(this);
                this.type = 'child';
            }
            let child = new Child();
            console.log(child);
            console.log(child.name);
            console.log(child.getName());
        </script>

3. Composition inheritance

Composition inheritance is a combination of the previous two methods.

code show as below:

        <script>
            function Parent() {
                this.name = 'parent';
                this.friends = ['zs', 'lisi', 'wangwu '];
            }

            // 为Parent原型对象上添加方法
            Parent.prototype.getName = function () {
                return this.name;
            };

            function Child() {
                Parent.call(this);
                this.type = 'child';
            }

            Child.prototype = new Parent();
            // 手动挂载构造器
            Child.prototype.constructor = Child;
            let child1 = new Child();
            let child2 = new Child();
            child1.friends.push('sunqi');
            console.log(child1.friends, child2.friends); // 不互相影响
            console.log(child1.getName());
            console.log(child2.getName());
        </script>

Combined inheritance combines the advantages of the previous two inheritance methods . When instantiating Child, the constructor of the parent class is called. child1 and child2 are independent of each other and have their own values, so they do not affect each other. When the getName method is called At that time, there was no such method on the child1 and child2 methods, and I searched upwards to find the getName method on the prototype object of Parent.

 The printout results are as follows:

4. Prototype inheritance

Using the Object.create() method to realize the inheritance of ordinary objects

Object.create(proto, [propertiesObject])
This method creates a new object and specifies the prototype object of the object -------  proto

        <script>
            let parent = {
                name: 'parent',
                friends: ['zs', 'lisi', 'wangwu'],
                getName() {
                    return this.name;
                },
            };
            // 相当于 child.__proto__ == parent
            let child1 = Object.create(parent);
            console.log(child1.__proto__ == parent); // true
            // 为 child1 添加属性name
            child1.name = 'child1';
            child1.friends.push('sunqi');

            let child2 = Object.create(parent);
            child2.friends.push('child2');

            console.log(child1);
            console.log(child2);
            console.log(child1.name == child1.getName()); //true


            console.log(child1.friends); // ['zs', 'lisi', 'wangwu', 'sunqi', 'child2'] 
            console.log(child2.friends); // ['zs', 'lisi', 'wangwu', 'sunqi', 'child2']
        </script>

The output print results are as follows:

Both child1 and child2 do not have their own friend attribute, so they have to look up and find the friend method on the parent object, pointing to the same memory, because the Object.createmethod implements a shallow copy , and the reference type attributes of multiple instances point to the same memory, there is possibility of tampering

5. Parasitic inheritance

Parasitic inheritance is optimized on the basis of the above inheritance, and the ability of this shallow copy is used to enhance and add some methods

        <script>
            let parent = {
                name: 'parent',
                friends: ['zs', 'lisi', 'wangwu'],
                getName() {
                    return this.name;
                },
            };

            // 定义继承的方法,
            function clone(proto) {
                let clone = Object.create(proto);
                // 添加自己的方法
                clone.getFriends = function () {
                    return this.friends;
                };
                return clone;
            }

            let child = clone(parent);
            console.log(child.getName());  // parent
            console.log(child.getFriends()); // ['zs', 'lisi', 'wangwu']
        </script>

6. Parasitic compositional inheritance

Combination and the fifth parasitic method and the third combined method

 <script>
            function clone(parent, child) {
                // 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程
                child.prototype = Object.create(parent.prototype);
                child.prototype.constructor = child;
            }

            function Parent() {
                this.name = 'parent';
                this.play = [1, 2, 3];
            }
            Parent.prototype.getName = function () {
                return this.name;
            };
            function Child() {
                Parent.call(this);
                this.friends = 'child';
            }

            clone(Parent, Child);

            Child.prototype.getFriends = function () {
                return this.friends;
            };

            let child = new Child();
            console.log(child); //{friends:"child",name:"parent",play:[1,2,3],__proto__:Parent}
            console.log(child.getName()); // parent
            console.log(child.getFriends()); // child
        </script>

Schematic diagram of prototype chain inheritance

 

Through this method, we found that the instantiated object child instantiated by Child can instantiate its own properties and methods, and can also inherit the properties and methods of the prototype object.

 3. Summary

can be summed up with a picture

 Developers believe that parasitic compositional inheritance is the most ideal way of inheritance

Welcome everyone to discuss in the comment area and learn together

Guess you like

Origin blog.csdn.net/qq_63299825/article/details/131063255