new、原型和原型链
继承是编程里的一个常见思想。通过对父对象属性、方法的继承子对象可以不用编写相同的代码但能调用对应的属性、方法。
js通过原型来实现继承特性。
原型
在js中,在js中每一个对象都有一个自己的"父对象",这个"父对象"就叫做原型。
了解原型我们需要知道三个属性以及他们对应的含义
- __ proto__ :对象的一个属性,指向这个对象的原型。
- prototype :函数的独有属性,指向这个函数的原型。
- constructor:对象的一个函数,指向这个对象的构造函数。
这里需要特别提到的有两点。
1、__ proto__在ES标准定义里的属性名应该是[[prototype]],具体实现是由浏览器代理自己实现。不同的浏览器可能在实现[[prototype]]上命名不同,功能是一致的。本文采用谷歌浏览器的实现命名方式__ proto__。
2、prototype是函数特有的属性,对象变量并没有prototype属性指向原型。但是由于函数也是一种对象,所以函数既有prototype,又有__ proto__,还有指向构造函数的constructor属性。
javascript
let func = function(value){
this.value = value
}
func.prototype.getValue = function() {
return this.value;
}
let objA = new func(4);
这段代码是一个简单的通过new关键字将func函数作为构造函数来实例化一个对象objA
。
func()是一个构造函数,它有着特殊的属性prototype
,在js中函数也是对象,所以它也有__ proto__
和constructor
。prototype
和__ proto__
都指向原型func.prototype。 constructor
指向func()的构造函数,这个在之后的原型链部分再讲。
func.prototype是一个原型对象,它也有__ proto__
和constructor
。在js中一个构造函数的它的constructor
指向构造函数
objA作为对象他有两个元素,__ proto__
和constructor
。constructor
指向构造函数func(), __ proto__
指向原型。由于new关键字在实例化对象时是将构造函数的原型赋给实例化对象,所以__ proto__
指向的是func.prototype。
func
的prototype和objA
的__ proto__都指向func.prototype
,objA
和func.prototype
的构造函数(constructor)都是func

new
通过new关键字调用一个函数时,将其视为一个构造函数,创建一个该构造函数的实例对象。这个对象拥有这个函数的共享属性、共享方法。具体实现在这里先不展示,需要知道的是: 在实例化这个对象的过程中,new将构造函数的prototype赋给了实例对象。
所以实例对象和构造函数实际上是共享一个原型。
原型链
对象有原型和构造函数,原型对象和构造函数也不例外。它们都有自己的原型和构造函数。 调用一个对象没有的方法时,该对象就会查找它的原型[[prototype]]查看是否有该方法,如果它的原型也没有该方法就会查找它原型的原型,直到查到Object.prototype。因为Object.prototype的原型是null。
这个通过[[prototype]]将各个原型穿起来链接就叫原型链。

如图所示从上到下分层来进行对这个原型链的解析。
第一层
: ObjA是func()实例化对象,所以func()是ObjA的构造函数。在js内部,每个函数都是由Function()实例化而来所以Function()是fun()的构造函数。这里需要注意一点,其实ObjA自身是没有constructor属性的,在查询constructor属性时是遍历到自身的原型然后调用的原型的constructor。
所以实例对象的constructor == 实例对象的原型的constructor
Function()函数比较特殊,它自己就是自己的构造函数。
第二层
:objA在实例化时func()将自身的原型赋给了它,所以objA和func()是同一原型。 由于ObjA是对象。所以只有__ proto__属性指向func.prototype。
每个构造函数在创建时,它的原型的constructor会自动指向它本身。 所以func.prototype.constructor == func。
同样Function.prototype.constructor指向Function()
第三层
:由于fun.prototype是一个对象且它不是由其它构造函数构造得来,所以它的原型是Object.prototype,func.prototype.__ proto__ == Object.prototype。
Function.prototype作为一个Function()的原型对象,自然它的原型也指向Object.prototype,Function.prototype.__ proto__ == Object.prototype。
Object()是Object的构造函数,所以Object().prototype.constructor == Object()
第四层
:Object()作为最上层的对象,所有的对象都是从Object.prototype直接或间接继承而来。所以Object()再往上没有原型。 Object.prototype == null
补充一下:
\[prototype\]\]可以通过Object.setPrototypeOf修改构造函数的原型,但是不建议这么做,因为构造函数在修改原型时不会一同修改 ```javascript let func = function(value){ this.value = value } func.prototype.getValue = function() { return this.value; } let objA = new func(4); console.log(objA.value) let o = function(value){ this.value = value + 1 } Object.setPrototypeOf(func.prototype, o.prototype) let objB = new func(2); console.log(objB.value) ```