深度理解原型链
1 function parent(){ this.parent = "world";2 }3 parent.prototype = {4 a : function(){5 },6 b : "hello"7 }8 var child = new parent()
? ?而child就是parent的一个实例,在执行构造函数的时候,js引擎创建一个空白对象,把__proto__指向parent的 prototype,然后把这个对象作为this调用parent进行初始化,这样一个简单的原型链就形成了 即 child --> parent.prototye -->Object.prototype。
? prototype,constructor,__proto__ :?
上面多次提到这几个属性,在原型链的概念中,如果能理解这几个属性的关系,那么离胜利就不远了。下面我们逐一的谈谈这几个属性:
1.prototype
prototype是构造函数的属性,指的就是构造函数的原型,在生成实例的时候,js会根据构造函数的prototype属性将该属性下的对象生成为父类,
? ? ?注意,只有构造函数这个属性才有这种效果哦~如果一个构造函数没有指定该属性,那么该属性下的__proto__会默认的指向原生Object的原型对象,该属性会变成一个对象,其中constructor属性指向本身。
2.constructor
? ? ?constructor,如果通俗的理解,可以理解成原型对象的构造函数,当把一个对象(对象字面量)赋给一个构造函数的原型,constructor 会被复写,如果没有进行prototype的操作的话,constructor是函数声明时指定的,指定为本身:
例如:
function A() {}
则 A.prototype.constructor === A;
但是这个属性往往是不准确的:
1 function parent(){ 2 this.a = "world"; 3 this.b = "world"; 4 } 5 parent.prototype = { 6 a : "aaa", 7 b : "bbb", 8 c : "!" 9 }10 function temp(){11 this.a = "hello";12 }13 temp.prototype = new parent();14 var child = new temp();15 console.log(child.a +" " + child.b+child.c);//hello world!
上面的代码运行结果就为 : “hello world!”生成的原型链即是
child(temp的实例) > __proto__ > temp.prototype(parent的实例) > __proto__ ?>parent.prototype > __proto__ >?Object.prototype >__proto__ > null
3.原型链的调用
如上所示,原型链由__proto__属性串联而成,经过上面的分析,调用的理解就变得很简单了,比如上例的原型链中,当调用child.c属性时,那么程序会按如下方式运行:
在child本层查找c,查询未果,会通过__proto__属性向上查找temp.prototype,查找未果,继续沿着 __proto__向上查找parent.prototype,oyeah~终于找到了~所以child.c在这里就会是 parent.prototype.c了~
怎么样,简单吧^ ^
?
最后的最后,呈上一个常用函数给大家:
1 function A() { 2 // do something here 3 } 4 A.prototype = { 5 a : 'aaa', 6 b : function() { 7 } 8 }; 9 function B() {10 }11 extend(B, A);12 function extend(child, parent) {13 function temp() {14 this.constructor = child;15 }16 temp.prototype = parent.prototype;17 child.prototype = new temp();18 }
extend函数 两个参数都为构造函数,目的是让一个构造函数(子类)继承另一个构造函数(父类)的原型,并且不调用父类的构造函数(有时候构造函数会需要一些参数或者做一些事情破坏了原型链),这个方法可以用来生成想要的原型链哦。