JS object-oriented chapter IV prototype chain and inheritance (multiple inheritance implementation and analysis of the pros and cons)

The film article content:
1, what is the prototype chain;
2, using the prototype implementation inheritance chain;
3, borrow constructor inheritance;
4. The composition inherited (the most common mode of inheritance);
5, prototypal inheritance: the Object.create ( );
6, parasitic inherited, inherited parasitic combination (optimal paradigm inherited);

Introduction .....

Due to the long length of this article, we avoid chaos after reading tricks, or to further clarify the next major content in detail. What we are first introduced the prototype chain to understand the concept of the prototype chain of knowledge can learn more inheritance, already known to be skipped. Because javascript inheritance relies mainly on the prototype chain to achieve, of course, we realize there are many inherited ways, above, there are listed, wherein the combination of inheritance is the most common way, because it is the constructor in two ways by the prototype chain and borrow binding come, so you can first understand simple method constructor and prototype inheritance chain borrowing. The remaining prototypal inheritance and Parasitic inheritance, are inherited parasitic combined for the final groundwork done, because the most common parasitic combined inherit inheritance compared to a combination of more efficient, so this is the best way of inheritance paradigm .

Prototype chain

Due to previous articles have been written about in detail prototype, then first look at the relationship between prototype, constructor and instance objects, keep in mind the following rules, which is the basis for understanding the prototype chain:
each has a constructor a property called prototype, this property is a pointer to an object that is the prototype;
every prototype object will get a default constructor property that points back to another constructor;
each instance of the object has an internal attributes [[prototype]], this attribute points to create a prototype property values of its constructor, which is the prototype object;
when trying to get a property of an object, if the object itself does not have this property, then it's going to [[prototype]] (i.e., the prototype its constructor) find.

Since many browsers can gain access to the inside of the object [[prototype]] property by __proto__, so the next discussion we will use __proto__ instead of [[prototype]].

That the above rules, the prototype chain is actually from an object, each object has a __proto__ attribute, which points to the value of the prototype property of the constructor of the object, the prototype object, while the prototype object itself is a target , it itself has a __proto__ attribute that point again prototype property values of the prototype object constructor, and so on, so that this chain is formed by the associated attribute of the object is __proto__ prototype chain.
Here we must bear in mind that a problem, because then the default instance of Object prototype all functions are all objects are by new Object () was created.

function Person(name) {
    this.name = name;
}
var p = new Person();
console.log( p.__proto__ == Person.prototype);//true,实例对象p的__proto__属性指向函数Person的prototype属性值;
console.log(p.__proto__.constructor);//结果:ƒ Person(name) {this.name = name;},p的构造函数为Person函数
console.log(Person.prototype.__proto__.constructor);//ƒ Object() { [native code] },Person.prototype这个对象的构造函数(即Person.prototype这个对象的__proto__中的constructor属性)为Object
console.log(Object.prototype == Person.prototype.__proto__);//因此Person.prototype对象的__proto__属性指向它的构造函数Object的prototype
console.log(Object.prototype.__proto__);//null,再向上一层去找Object的原型(Object.prototype)也是一个对象,它的原型为null;

Note that the above code because the print Person.prototype
code above prototype chain is formed: p -> p .__ proto __ (Person.prototype) -> Person.prototype .__ proto __ (Object.prototype) -> null, as shown below shows:
Here Insert Picture Description
here If you do not understand it does not matter, read the following prototype inheritance chain can be more clear understanding of the prototype chain.

Prototype inheritance chain

javascript Inheritance mainly rely on the prototype chain to achieve the basic idea is to use a prototype, so a reference type inherits from another type of reference properties and methods.
DETAILED rewrite approach is to create a reference to the prototype object type constructor A reference to another type b.

function Father () {
    this.fatherName = 'dad'
}
Father.prototype.say = function () {
    console.log(this.fatherName)
}
function Child () {
    this.childName = 'son'
}
Child.prototype = new Father()
Child.prototype.sing = function () {
    console.log('hello dad')
}
var c = new Child()
c.say() // dad

Use the prototype, we will sub-type prototype constructor Child rewrite instance of the parent type, so that when the instance of a subtype of c on a property access, will first look at the instance c of this, if not found, then go back c prototype object, which is to look for the Child.prototype, but this time point are examples Child.prototype father, thereby achieving a subtype supertype instance access properties and methods (including the parent object and the prototype object instance all properties and methods), implements inheritance.
Here Insert Picture Description
The default is the prototype of all functions Object instance , so Father.prototype is the Object instance, so Father.prototype .__ proto__ is Object.prototype, Object.prototype is a target, looking up Object.prototype this object is the prototype null.

Precautions

This use of prototype inheritance chain problem with the way a particular note: If you need to add your own methods or parent type of method to cover the child from the type of prototype, you must add the method code written statement after the replacement prototype, otherwise it will not be found. Further in the alternative can not be reduced since the constructor type after another example, then the literal manner from the type adding method to do so from the parent type contact type will be cut, can no longer be achieved inheritance.

function Father () {
    this.fatherName = 'dad'
}
Father.prototype.say = function () {
    console.log(this.fatherName)
}
function Child () {
    this.name = 'son'
}
//1、先替换原型
Child.prototype = new Father()
//2、再添加方法
Child.prototype.sing = function () {
    console.log('hello dad')
}
//3、若添加方法像下面这样使用字面量方式就不能实现继承了
//Child.prototype = {
//  sing : function () {
//      console.log('hello dad')
//  }
//}
var c = new Child()
c.say() // dad
Problems

One problem: the prototype reference type attribute will be instances of all subtypes shared, modified interaction therebetween;
problem: no way to pass parameters as constructor of the parent type, so that all instances dynamically set its property value;
based on the above prototype chain is rarely used alone to achieve inheritance.

Borrowing Constructor

这种方式的基本思想:在自类型构造函数内部,利用call或apply方法调用父类型构造函数,传入当前作用域,即this,就可以添加每个子类型实例自己的属性了。
因为每个自实例都拥有自己的属性,所以避免了共享属性带来的相互影响的问题。另外,call方法除了可以传一个this,还可以传其他的参数给父类型构造函数,从而动态设置子类型的属性值。

function Father (name, age) {
    this.name = name
    this.age = age
    this.interest = ['sing', 'book']
}
function Child (name, age, sex) {
    //继承了Father,同时传递了参数给父类型构造函数
    Father.call(this, name, age)
}
var sister = new Father('Amy', 18)
var brother = new Father('Tom', 14)
sister.interest.push('paint')
console.log(sister.interest) // ['sing', 'book', 'paint']
console.log(brother.interest) // ['sing', 'book']

如果单独使用借用构造函数的方法实现继承,那么方法就只能定义在构造函数中了,那么就会变成创建n个实例,产生n个同样的函数,就没有函数复用可言了。所以我们也很少单独使用这种方式。

组合继承

结合原型链与借用构造函数实现继承的两种方法来实现继承叫组合继承。
基本思想就是:原型链实现原型上的可共享属性和方法的继承,借用构造函数实现父类型实例属性的继承。

function Father (name, age) {
    this.name = name
    this.age = age
    this.interest = ['sing', 'book']
}
Father.prototype.say = function () {
    console.log('hello my children')
}
function Child (name, age, sex) {
    //继承父类型属性
    Father.call(this, name, age)
    this.sex = sex
}
//继承方法
Child.prototype = new Father()
Child.prototype.constructor = Child
Child.prototype.sing = function () {
    console.log('hello dad')
}
var sister = new Father('Amy', 18, 'girl')
var brother = new Father('Tom', 14, 'boy')
sister.interest.push('paint')
console.log(sister.interest) // ['sing', 'book', 'paint']
console.log(brother.interest) // ['sing', 'book']
console.log(sister.name) // Amy
console.log(brother.name) // Tom

组合继承方式是javascript中最常用的继承模式。

原型式继承:Object.create()

基本思想:借助原型基于已有的对象创建新对象。

function object (o) {
    function F() {}
    F.prototype = o
    return new F()
}

以上代码可以看出,这个object函数的作用就是,返回一个继承给定对象的新对象。如:

var father = {
    name : 'zhangsan',
    age : 40,
    interest : ['sing', 'book'],
    sayName : function () {
        console.log(this.name)
    }
}
var child1 = object(father)
var child2 = object(father)
console.log(child1.name)
console.log(child2.name)
child1.interest.push('paint')
console.log(child1.interest) // ['sing', 'book', 'paint']
console.log(child2.interest) // ['sing', 'book', 'paint']

通过这种方式可以创建两个继承father对象的实例对象child1、child2。
ECMAScript通过新增的Object.create()方法规范化了原型式继承。
这个方法接收两个参数,使用方法如下:

var father = {
    name : 'youyang',
}
var child = Object.create(father, {
    name : {
        value : 'xiaoqu'
    }
})
console.log(child.name) // xiaoqu

Object.create()方法的第二个参数与Object.defineProperties()方法的第二个参数格式相同,关于Object.defineProperties()方法的使用以及属性描述符相关问题可以阅读这篇文章:理解对象及属性特性(属性描述符)

注意事项

Prototypal inheritance actually return a copy of a specified object only.
But thinking Object.create () method is only a method of creating an object, but the object's prototype for a specified object

Problems

Supertype reference type attribute type from shared example, affect each other modified.

Prototypal inheritance in the case just want to make one object to another object similar, there is no need to create a fully competent when constructor.

Parasitic inheritance

Parasitic inheritance prototypal inheritance is based on extensions to the, also stressed before the prototype formula inherited only returns a copy of the specified object, so prototypal inheritance does not add to the subtypes of their own properties and methods.
Parasitic inheritance idea is: still inside a function, use the prototype to create a new object based on an existing object, except to add some properties and methods of their own for the new object.

function createAnother (o) {
    var another = object(o) // object是原型式继承中的那个object函数
    another.sayHello = function () {
        console.log('hello world')
    }
    return another
}

CreateAnother above function is implemented Parasitic package inheritance.

var father = {
    name : 'youyang',
}
var child = createAnother(father)
child.sayHello() // hello world
Problems

This way is to add a sub-type function, but also still can not do multiplexing function, not an object is created, it will create a corresponding method (in this case sayHello), will reduce efficiency.

Combined parasitic inheritance

Speaking in front of a combination of inheritance is the most common mode of inheritance, but in this way but it is still inadequate, its problem is to perform two types of parent constructor. You can look at the code before combining inheritance, respectively, within the sub-type constructor called once, and when the rewrite from type constructor prototype called once again by the call method.
The so-called parasitic inheritance is combined with a combination of inheritance and succession Parasitic two ways to implement inheritance, the specific idea is: a subtype of a parent type constructor prototype rewrite instance instead rewrite copy of the parent type constructor prototype object.

function createAnotherPrototype(Father, Child) {
    var another = object(Father.prototype)
    another.constructor = Child
    Child.prototype = another
}

These are inherited parasitic modular core code, so long as the composition example in succession Child.prototype = new Father () This line of code to call the function can be packaged above: createAnotherPrototype (Father, Child);

Developers generally agreed that the combined parasitic inheritance are reference types inherit the best paradigm!

Guess you like

Origin www.cnblogs.com/youyang-2018/p/11777076.html