[我的敞亮]Javascript的原型与原型链

一、原型与原型链的概念

  • 原型:为此外对象提供共享属性的目标

   
注:当构造器创立一个目标,为了缓解对象的性质引用,该对象会隐式引用构造器的”prototype”属性。程序通过constructor.prototype可以一向引用到构造器的”prototype”属性。并且增长到目标原型里的属性,会经过持续与持有共享此原型的目的共享。

  • 原型链:每个由构造器创立的靶子,都有一个隐式引用(叫做对象的原型)链接到构造器的”prototype”属性。再者,原型可能有一个非空隐式引用链接到它和谐的原型,以此类推,这称为
    原型链

二、ES5中的Function与Object类型

知情Function与Object类型的里边的涉及,对大家精通原型和原型链有很首要的扶持。

var fn = Function;
console.log("fn的原型:" + fn.prototype);
console.log("fn的原型链:" + fn.__proto__); 
console.log("fn的原型等于fn的原型链:" + ( fn.prototype === fn.__proto__ ) );
console.log("fn的原型的原型链:" + fn.prototype.__proto__);
var obj = Object;
console.info("obj的原型:" + obj.prototype);
console.info("obj的原型链:" + obj.__proto__);
console.info("obj的原型不等于obj的原型链:" + (obj.prototype === obj.__proto__));
console.info("obj的原型的原型链:" + obj.prototype.__proto__);

输出结果如下:

fn的原型:function () {}
fn的原型链:function () {}
fn的原型等于fn的原型链:true
fn的原型的原型链:[object Object]
obj的原型:[object Object]
obj的原型链:function () {}
obj的原型不等于obj的原型链:false
obj的原型的原型链:null

遵照输出结果我们不难看出,Function与Object存在相互引用的关联,以及另外特色总结如下:

  • ECMAScript,Function.prototype.proto ===
    Object.prototype:Function的原型的原型链等于Object的原型
  • Function.proto ===
    Object.proto:Function与Object的原型链是相等的
  • Function.proto ===
    Function.prototype:Function的原型等于Function的原型链,在ECMAScript5.1的标准中是这么说明的:Function的prototype是一个函数对象,他里面的[[prototype]]属性值是正规内置的Object的prototype对象
  • Object.prototype.proto === null:Object的原型的原型链为null

关系图:

ECMAScript 1

  • Function的prototype的__proto__是援引的Object的prototype,这是Function的原型的原型链
  • 而Object的__proto__是援引了Function的prototype的。

2.1、其他原生类型

原生类型大概能够分两类,一类是继承于Function的,另一类是持续于Object。

  • 继承于Function类型:String、Number、Boolean、Array、Date、RegExp、Error等,他们的__proto__(原型链)都指向了Function,而她们的prototype是各自类型的正规内置对象,这也就注明她们的prototype是继承于Object的,所以prototype.__proto__指向Object的prototype。
  • 继承于Object类型:Math、JSON等。因为是目的,所以没有构造函数,也绝非协调的嵌入原型对象(prototype属性)。但要么有原型链的,他的__proto__指向Object的prototype。

2.2、总结

  • Function是函数(类)的根底原型
  • Object是目的的功底原型
  • 运转时成立一个目标,会将构造器的prototype属性引用复制给目标的__proto__上,这里的创设一个对象,只好是new格局。
  • 用function关键字定义的类,做为Function类型的实例他自个儿有一个原型链(本身继承于Object),另外通过new创造的实例对象也有属于自己的原型链(prototype到__proto__的转换)。

三、实现持续(原型继承)

    
前边描述了Function、Object和其它原生类型的涉嫌,在此处我们深刻明白Function对象的类特性,那里我们拔取function这些类,他是Function的实例,拥有Function类型的保有办法。

3.1、ES5.1

function Parent(){
    this.name = 'parent';
}
Parent.prototype.getName = function(){
    console.log(this.name);
}

function Child(){
    Parent.call(this); //在this对象上增加属性
    this.cName = 'child';
}
Child.prototype = Parent.prototype; //复制parent的prototype所有的内容,包含构造器
Child.prototype.constructor = Child; //恢复构造器为子类,不恢复也不影响其new

var _child = new Child();

贯彻连续的步调:

  • Parent的prototype赋值给Child的prototype,使其Child拥有Parent的原型方法或性质(子类与父类的prototype举办联合)
  • 将Child.prototype.constructor指向Child函数,因为constructor是指向其构造器的措施,被Parent赋值后,其实是指向了Parent的构造器,所以需要改回来。
  • 在Child的构造器中用Call执行Parent的构造器,实例构造器的继续执行(顺序执行父类、子类的构造函数)。

总结:

  • 原型的继承实际上是共享原型上的习性和格局,所以更改基类原型上的特性和格局会影响到子类。但构造器中对this做的绑定则是实例独立的。
  • function关键字定义的类(Parent、Child)的__proto__都是指向function的构造函数
  • function关键字定义的类具有prototype的__proto__都是指向了Object的prototype。

3.2、ES2015(ES6)

在es6中贯彻持续就一定的简短了,不需要像es5中那么步骤来落实,继承实现如下:

class Parent {
    constructor(){
        this.name = 'parent';
    }
    getName(){
        console.log(this.name);
    }
}
class Child extends Parent {
    constructor(){
        super();
        this.cName = 'child';
    }
}

var _child = new Child();
  • Class的__proto__本着父类的概念,包含构造函数。
  • Class的prototype.__proto__是指向父类的prototype,表示方法的存续。

四、爆发的变动

  • ES5中用Function实现面向对象,而ES6提供了Class。
  • ES6的Class对原型与原型链更加规范化。
  • ES6提供了操作__proto__对象的主意,分别如下:
    • Object.setPrototypeOf(obj,protype):设置对象的__proto__(原型对象
    • Object.getPrototypeOf(obj):读取对象的__proto__(原型对象)
  • ES5中得以一向对__proto__赋值,但不指出如此使用。
  • ES5中对子类的prototype举行赋值后,还亟需重定向prototype.constructor到子类的构造函数。