[Front-end knowledge related -JS]-depth understanding of JavaScript Prototype (inherited) and the prototype chain

1. Javascript inheritance

1.1 prototype chain to inherit

    function Parent() {
      this.name = 'zhangsan';
      this.children = ['A', 'B', 'C'];
    }
    Parent.prototype.getName = function() {
      console.log(this.name);
    }
    
    function Child() {
      
    }
    Child.prototype = new Parent();
    var child = new Child();
    console.log(child.getName());

[! NOTE]
main issues:

  1. Reference type is shared by all instances of attributes (this.children.push ( 'name'))
  2. When creating an instance of the Child, we can not pass parameters to Parent

1.2 borrow Constructor (classical inheritance)

    function Parent(age) {
      this.names = ['zhangsan', 'lisi'];
      this.age = age;
      
      this.getName = function() {
        return this.names;
      }
      
      this.getAge = function() {
        return this.age;
      }
    }
    
    function Child(age) {
      Parent.call(this, age);
    }
    var child = new Child(18);
    child.names.push('haha');
    console.log(child.names);
    
    var child2 = new Child(20);
    child2.names.push('yaya');
    console.log(child2.names);

[! NOTE]
advantages:

  1. Avoiding the reference type of property is shared by all instances
  2. Reference may be directly transmitted to the Parent Child in

[! DANGER]
Disadvantages:

  • Methods are defined in the constructor, each instance is created again create method

1.3 combination of inheritance (the prototype chain of inheritance and succession classic two-pronged approach)

    /**
    * 父类构造函数
    * @param name
    * @constructor
    */
    function Parent(name) {
      this.name = name;
      this.colors = ['red', 'green', 'blue'];
    }
    
    Parent.prototype.getName = function() {
      console.log(this.name);
    }
    
    // child
    function Child(name, age) {
      Parent.call(this, name);
      this.age = age;
    }
    
    Child.prototype = new Parent();
    // 校正child的构造函数
    Child.prototype.constructor = Child;
    
    // 创建实例
    var child1 = new Child('zhangsan', 18);
    child1.colors.push('orange');
    console.log(child1.name, child1.age, child1.colors);    // zhangsan 18 (4) ["red", "green", "blue", "orange"]
    
    var child2 = new Child('lisi', 28);
    console.log(child2.name, child2.age, child2.colors);    // lisi 28 (3) ["red", "green", "blue"]

[NOTE!]
Advantages: combines the advantages of the prototype inheritance chain and constructors, Javascript is the most commonly used mode of inheritance

2. A variety of ways inherited advantages and disadvantages of summary

2.1 prototypal inheritance

    function createObj(o) {
      function F(){};
      // 关键:将传入的对象作为创建对象的原型
      F.prototype = o;
      return new F();
    }
    
    // test
    var person = {
        name: 'zhangsan',
        friends: ['lisi', 'wangwu']
    }
    var person1 = createObj(person);
    var person2 = createObj(person);
    
    person1.name = 'wangdachui';
    console.log(person1.name, person2.name);  // wangdachui, zhangsan
    
    person1.friends.push('songxiaobao');
    console.log(person2.friends);       // lisi wangwu songxiaobao

[! DANGER]
Disadvantages:

  • For the property values ​​of reference types are always shared the corresponding value, and the prototype chain to inherit the same

2.2 Parasitic inheritance

    // 创建一个用于封装继承过程的函数,这个函数在内部以某种形式来增强对象
    function createObj(o) {
      var clone = Object.create(o);
      clone.sayName = function() {
        console.log('say HelloWorld');
      }
      return clone;
    }

[DANGER!]
Cons: borrow constructors and patterns, creating an object is created each time the method again

2.3 Inheritance parasitic combined

2.3.1 basic version

    function Parent(name) {
      this.name = name;
      this.colors = ['red', 'green', 'blue'];
    }
    
    Parent.prototype.getName = function() {
      console.log(this, name);
    }
    
    function Child(name, age) {
      Parent.call(this, name);
      this.age = age;
    }
    
    // test1:
    // 1. 设置子类实例的时候会调用父类的构造函数
    Child.prototype = new Parent();
    // 2. 创建子类实例的时候也会调用父类的构造函数
    var child1 = new Child('zhangsan', 18);   // Parent.call(this, name);
    
    
    // 思考:如何减少父类构造函数的调用次数呢?
    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    
    // 思考:下面的这一句话可以吗?
    /* 分析:因为此时Child.prototype和Parent.prototype此时指向的是同一个对象,
            因此部分数据相当于此时是共享的(引用)。
            比如此时增加 Child.prototype.testProp = 1; 
            同时会影响 Parent.prototype 的属性的。
          如果不模拟,直接上 es5 的话应该是下面这样吧
          Child.prototype = Object.create(Parent.prototype);*/
    Child.prototype = Parent.prototype;
    
    // 上面的三句话可以简化为下面的一句话
    Child.prototype = Object.create(Parent.prototype);
    
    
    
    // test2:
    var child2 = new Child('lisi', 24);

Optimized version 2.3.2

    // 自封装一个继承的方法
    function object(o) {
      // 下面的三句话实际上就是类似于:var o = Object.create(o.prototype)
      function F(){};
      F.prototype = o.prototype;
      return new F();
    }
    
    function prototype(child, parent) {
      var prototype = object(parent.prototype);
      // 维护原型对象prototype里面的constructor属性
      prototype.constructor = child;
      child.prototype = prototype;
    }
    
    // 调用的时候
    prototype(Child, Parent)

3. The method of creating an object JS

  • Literal creation
  • Constructor creates
  • Object.create()
var o1 = {name: 'value'};
var o2 = new Object({name: 'value'});

var M = function() {this.name = 'o3'};
var o3 = new M();

var P = {name: 'o4'};
var o4 = Object.create(P)

4. prototype and prototype chain

4.1 Prototype

  1. All objects are included in the JavaScript an __proto__internal attribute, the corresponding is the prototype of the object
  2. JavaScript function objects, in addition to the prototype __proto__, but also the pre-prototype property
  3. When the function creates an instance of an object as a constructor, which is the prototype property value as a prototype example of an object __proto__.

prototype

4.2 prototype chain

  1. Any object can be an instance of its corresponding prototype object found by prototype chain, the above prototype object instance and instance methods are shared.

  2. When an object to find a method or property, he will first go on their own objects, when found, he will in turn look up the prototype chain.

[NOTE!]
Note: The only function prototype, instance of the object only has __proto__, while some __proto__ function because the function is an instance of an object Function

4.3 instanceof principle

[! NOTE]
the prototype the __proto__ attribute constructors instance object is not determined by a reference. If not, he looks up along __proto__ object until the top Object.

4.4 is a direct target is determined which instance of the class

[! NOTE]
used 对象.construcordirectly can be determined

4.5 constructor, what happens when the new?

   var obj  = {}; 
   obj.__proto__ = Base.prototype;
   Base.call(obj);  
  1. Create a new object obj;
  2. The __proto__ members of this empty object points to the member object prototype function objects Base
  3. Base this pointer replace function object obj, equivalent to the implementation of Base.call (obj);
  4. If the constructor returns a displayed object, then the object is returned in this example for this. Otherwise, it returns the newly created object

4.6 Class

// 普通写法
function Animal() {
  this.name = 'name'
}

// ES6
class Animal2 {
  constructor () {
    this.name = 'name';
  }
}

Guess you like

Origin www.cnblogs.com/fecommunity/p/11922158.html