JS原型继承与原型链(一)

一、prototype

用构造函数生成实例对象,有一个缺点,那就是无法共享属性和方法。比如,在DOG对象的构造函数中,设置一个实例对象的共有属性species。

function DOG(name){

  this.name = name;

  this.species = '犬科';

}

然后,生成两个实例对象:

var dogA = new DOG('大毛');

var dogB = new DOG('二毛');

这两个对象的species属性是独立的,修改其中一个,不会影响到另一个。

dogA.species = '猫科';

alert(dogB.species); // 显示"犬科",不受dogA的影响

每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。考虑到这一点,Brendan Eich决定为构造函数设置一个prototype属性。

这个属性包含一个对象(以下简称"prototype对象"),所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。

function DOG(name){

  this.name = name;

}

DOG.prototype = { species : '犬科' };

var dogA = new DOG('大毛');

var dogB = new DOG('二毛');

alert(dogA.species); // 犬科

alert(dogB.species); // 犬科

现在,species属性放在prototype对象里,是两个实例对象共享的。只要修改了prototype对象,就会同时影响到两个实例对象。

二、__proto__

我们创建的每一个函数都有一个 prototype 属性,这个属性是一个指针,指向一个对象。这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,简单来说,该函数实例化的所有对象的__proto__的属性指向这个对象,它是该函数所有实例化对象的原型。

通用规则:

  • 对象__proto__属性,函数prototype属性;
  • 对象函数生成;
  • 生成对象时,对象__proto__属性指向函数prototype属性。
//创建空对象时,实际上我们是用Object函数来生成对象的:
var o = {}
o.__proto__ === Object.prototype
//true

//我们也可以显式的使用Object函数来创建对象:
var o = Object()
o.__proto__ === Object.prototype
//true

//当我们使用函数来创建自定义的对象时,上面的规则同样适用:
function MyObj(){}
typeof MyObj
//"function"
var mo = new MyObj()
mo.__proto__ === MyObj.prototype
//true

既然JavaScript里“一切皆对象”,那函数自然也是对象的一种。对于函数作为对象来说,上面的规则同样适用:

//函数对象都是由Function函数生成的:
function fn(){}
fn.__proto__ === Function.prototype
//true

//Function函数本身作为对象时,生成它的函数是他自身!
Function.__proto__ === Function.prototype
//true

//Object函数既然是函数,那生成它的函数自然是Function函数咯:
Object.__proto__ === Function.prototype
//true

三、prototype与__proto__

对象的__proto__属性是从生成它的函数的prototype那里得来的
一般函数默认的prototype是一个类型为"object"的对象,它有两个属性:constructor__proto__。其中constructor属性指向这个函数自身,__proto__属性指向Object.prototype,这说明一般函数的prototype属性是由Object函数生成的。
大多数情况下,__proto__可以理解为“构造器的原型”,即__proto__===constructor.protype
特殊情况:
Object函数特殊情况:Object.prototype.__proto__ === null,我们知道,这就是JavaScript原型链的终点了。
Fuction函数特殊情况:Function.prototype.__proto__ === Object.prototype  Function函数的prototype属性是一个"function"类型的对象,而不像其他函数是类型为"object"的对象。
为什么要这样设定呢?
typeof Object.prototype === "object",说明它是一个Object对象,如果它由Object函数生成,于是按照我们上面的通用规则,就该是Object.prototype.__proto__ === Object.prototype
啊哈,问题出现了,Object.prototype.__proto__属性指向了它自身,这样以__proto__属性构成的原型链就再也没有终点了!所以为了让原型链有终点,在原型链的最顶端,JavaScript规定了Object.prototype.__proto__ === null
按照我们最开始提出的通用规则,一个"function"类型的对象,应该是由Function函数生成的,那它的prototype属性应该指向Function.prototype,也就是Function.prototype.__proto__ === Function.prototype。和Object函数同样的问题出现了:循环引用。所以JavaScript规定Function.prototype.__proto__ === Object.prototype,这样既避免了出现循环引用,又让__proto__构成的原型链指向了唯一的终点:Object.prototype.__proto__ === null
 
四、原型链

参考资料:

http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

http://cavszhouyou.top/JavaScript%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E4%B9%8B%E5%8E%9F%E5%9E%8B%E4%B8%8E%E5%8E%9F%E5%9E%8B%E9%93%BE.html

https://www.jianshu.com/p/686b61c4a43d

https://www.jianshu.com/p/08c07a953fa0

原文地址:https://www.cnblogs.com/fmyao/p/12558848.html