8条规则图解JavaScript原型链继承原理
原形链是JS难点之一,而且很多书都喜欢用一大堆的文字解释给你听什么什么是原型链,就算有图配上讲解,有的图也是点到为止,很难让人不产生疑惑。
我们先来看一段程序,友情提示sublimeText看更爽:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>《JavaScript高级程序设计(第三版)》Page163页的源码</title> <link href="" rel="stylesheet"> </head> <body> <script type="text/javascript"> function SuperType(){ this.property = "我是父亲的属性"; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = "我是孩子的属性"; } SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ return this.subproperty; } var instance = new SubType(); alert(instance.getSuperValue());//我是父亲的属性 </script> </body> </html>
有的人可能会觉得很熟悉,这是《JavaScript高级程序设计(第三版)》Page163页的源码。ps:将原来的false,true改成中文字符串比较容易看懂
但是下面的图我看了就觉得很怪了,原来的原型不是换了吗?怎么还指向呢?然后自己画了一个图并且证明了一遍,才发现原来书里画的也是错的。
然后就引出了想要图解原型链的想法,我们来看下面,友情提示sublimeText看更爽:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>JS原形链图解</title> </head> <body> <script type="text/javascript"> function SuperType(){ this.property = "我是父亲的属性"; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = "我是孩子的属性"; } var SubPro = SubType.prototype;//因为下面要改变原型,先用一个引用存起来,不然等下找不到 console.log("没改变原型之前是相等的:"+(SubType.prototype===SubPro)) SubType.prototype = new SuperType(); //这里改变了SubType的原型使它指向一个SuperType实例 console.log("给SubType构造函数换了原型之后是不等的:"+(SubType.prototype===SubPro)); //这里可以看出原型已经改变了 SubType.prototype.getSubValue = function(){ return this.subproperty; } var instance = new SubType(); //**************************** //下面开始证明图 //**************************** console.log("window对象下面添加了一个函数SuperType:"+(window.hasOwnProperty('SuperType'))); console.log("window对象下面添加了一个函数SubType:"+(window.hasOwnProperty('SubType'))); //下面全部为true console.log("1:"+(SuperType.prototype===SuperType.prototype)); console.log("2:"+(SuperType===SuperType.prototype.constructor)); //不能直接找到new SuperType,我们用5来获取 console.log("3:"+(SubType.prototype.__proto__===SuperType.prototype)); console.log("4:"+(SubType.prototype.constructor===SuperType)); console.log("5:上面3,4已经顺带一起证明了,而且直接看代码就可以看出来了"); //我们用SubPro暂存了原来的原型 console.log("6:"+(SubPro.constructor===SubType)); //还是因为取不到new SuperType,我们用SubType.prototype来获取 console.log("7:"+(instance.__proto__===SubType.prototype)); console.log("8:"+(instance.constructor===SuperType)); //**************************** //下面开始证明各自的属性位置 //**************************** console.log("instance有私有的subproperty属性:"+(instance.hasOwnProperty('subproperty'))); console.log("new SuperType有私有的property属性:"+(SubType.prototype.hasOwnProperty('property'))); console.log("SuperType.prototype拥有私有的getSuperValue属性:"+(SuperType.prototype.hasOwnProperty('getSuperValue'))); console.log("SubType.prototype(换过的原型)拥有私有的getSubValue属性:"+(SubType.prototype.hasOwnProperty('getSubValue'))); console.log("SubPro(原来的原型)拥有私有的getSubValue属性:"+(SubPro.hasOwnProperty('getSubValue')));//false原来的原型没有getSubValue函数,因为是换了原型再添加的函数,所以函数存在实例里面 </script> </body> </html>
下面梳理一下原型链继承:(点击看大图)
这里通过一个SuperType实例替换SubType的原来的原型,这里的SuperType实例本身就拥有SuperType构造函数以及SuperType.prototype自带的一些属性,那么当取代SubType.prototype(原来的)之后,自然而然的instance实例的属性找不到的要到SubType的原型里面去找,而原来的原型已经被替换了,那么新原型里面有的属性就成了instance可以找到的属性了。ps:这里文字真心不好表达,反正就是往构造函数和构造函数原型找的意思。
这里当然也发生了略微有点奇怪的两点:
- __proto__属性指向新原型(本来是指向旧的SubType.prototype也就是SubPro的),这里勉强可以理解,换了原型嘛!
- constructor指向了SuperType构造函数(没有改变原型的话是指向SubType构造函数的),无法理解,代码是var instance = new SubType();怎么顺便把constructor属性也换了?
但是问题存在我们依旧可以很好理解JS的原型链继承:通过新的实例继承父构造函数与其原型的属性,然后通过替换子构造函数原型达到继承的目的。
非常建议看过《JavaScript高级程序设计(第三版)》的童鞋看完上面之后回去把书里面原型链这一节看一下,对比一下。如果有问题请留言。万分感谢!如果觉得我写的有用的话请点个赞,这是对我最大的鼓励!么么哒^_^
原文地址:请点击这里