原型链这一个话题,需要和很多概念一起讲,才能串成一个比较系统的知识点。在这其中我们就逃不开要讨论继承、原型对象、构造函数、实例了。

一、构造函数

构造函数是一类特殊的函数,它的作用是用来生成实例对象。想要获得某一类型的构造函数可以用 class.prototype.constructor来获得,也可以对该属性进行赋值操作。
利用构造函数创建实例要用到new关键字,这个过程会有以下几步:
a.创建一个对象
b.将构造函数中的this指向该对象的引用
c.执行构造函数中的代码
d.返回该对象

二、原型对象(prototype)

在原型链中,原型对象是一个很关键的点。定义一个函数对象的时候,会包含一个预定义的原型对象,即Object的实例,所以原型对象是针对函数对象来讲的。

三、prototype vs _proto_

上面就提到一点prototype是指构造函数的原型对象,它是一个对象,它是构造函数的属性
而_proto_是一个实例对象的内部属性,用来指向创建该实例的函数对象的原型对象。
我们将在第五小节用代码更加直观得明白二者的关系

四、继承

在JavaScript中,我们可以用改变构造函数的原型对象来实现继承。

五、原型链

什么时候会出现原型链:当一个构造函数的原型对象(prototype)指向另一个引用类型的实例,该实例的构造函数的原型对象又包含一个指向另一个原型的指针。层层递进,就构成了实例与原型的链条。这也就是形成原型链的基本思路。
说个通俗的例子:

//父亲类构造函数
  function Father(){
    this.FProp = "father";
  }
  Father.prototype.FCall = function(){
    console.log(JSON.stringify(this)+" is calling father's function");
  }

  //儿子类构造函数
  function Son(){
    this.SProp = "son";
  }

  Son.prototype.SCall = function(){
    console.log("I'm a son");
  }

  //通过原型继承
  //注意上面的SCall()会失效,因为用了继承,prototype中的方法和constructor被重写
  Son.prototype = new Father();
  Son.prototype.constructor =  Son;
  //生成实例对象
  var newInstance = function(){
    var tom = new Son();
    tom.FCall();
    console.log(tom.FProp);
    //tom.SCall(); 控制台会报undefined错误
    console.log(tom.SProp);

    console.log(Son.prototype.constructor);
  }  

代码结果:
可以看出子类继承了父类之后,可以获取父类的属性和方法。
图片描述

  var getDifference = function(){
    var tom = new Son();
    console.log(Son.prototype); 
    console.log(tom.__proto__);
    console.log(tom.prototype);   
  }

代码结果:
对象实例获取prototype的结果是undefined
图片描述


青草怪味豆
95 声望4 粉丝

Practice Makes Perfect!