掌握 js 原型链,对理解 js 的指向有很大帮助,以下通过一个例子进行简单说明
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <script> 7 function Person( user ){ 8 this.userName = user; 9 }; 10 Person.prototype.showUserName = function(){ 11 return this.userName; 12 }; 13 14 var obj = new Object(); 15 obj.userName = "huanying2015"; 16 Person.prototype = obj; 17 18 var OP1 = new Person('zhangsan'); 19 // 结果分析:实例化一个对象OP1,传入参数"zhangsan",调用构造函数Person,把this.userName设置为"zhangsan",所以输出结果为"zhangsan" 20 console.log( OP1.userName ); // zhangsan 21 delete OP1.userName; 22 // 因为在第21行删除了OP1的 userName 属性,所以输出OP1,结果为空对象 23 console.log( OP1 ); // Person {} 24 // 因为在第16行改变了Person.prototype 的指向,所以此时Person.prototype 指向obj; OP1上没有userName属性,就往上查找原型链,最终找到obj上的userName 属性,所以输出huanying2015 25 console.log( OP1.userName ); // huanying2015 26 27 // OP1的隐式原型属性 __proto__ 指向 Person的原型对象即Person.prototype, 所以输出结果为 true 28 console.log( OP1.__proto__ === Person.prototype ); // true 29 // OP1.__proto__即是Person.prototype , 也就是obj(16行做的改变),相当于输出obj.userName ,所以结果为:huanying2015 30 console.log( OP1.__proto__.userName ); // huanying2015 31 32 var OP1 = new Person('wanger'); 33 // 重新实例化一个OP1,传入参数为“wanger”,经过调用构造函数Person,所以得到一个新对象 34 console.log( OP1 ); // Person { userName:"wanger"} 35 36 // OP1的隐式原型属性 __proto__ 指向 Person的原型对象即Person.prototype, 原型对象并没有改变,所以输出结果为 true 37 console.log( OP1.__proto__ === Person.prototype ); // true 38 // Person 的原型对象并没有改变什么,所以输出结果为 Object 39 console.log( Person.prototype ); // Object {userName:"huanying2015"} 40 41 // Person.prototype 的指向改变了(第16行),所以输出结果为false 42 console.log( Person.prototype.constructor === Person ); // falsse 43 // 实际上输出 Object(),因为指向在第 16 行改变了 44 console.log( Person.prototype.constructor ); // function Object() { [native code] } 45 // 在第16行指向改变了,所以原先在原型对象上的showUserName() 方法也就不存在了,调用不存在的方法,所以报错 46 OP1.showUserName(); //报错: Uncaught TypeError: OP1.showUserName is not a function 47 48 </script> 49 </head> 50 <body> 51 52 </body> 53 </html>
运行结果:
原型链说明:
/**************************************************************************************************************************************************
1. 任何一个函数,它的原型对象(prototype)上,都天生自带一个constructor 属性,这个属性指向函数的构造函数本身
2. 任何一个函数,都天生自带一个Prototype 属性,这个属性指向函数的原型对象
3. 任何一个对象(例如 :实例),都天生自带一个隐式原型__proto__属性,这个属性指向构造函数的原型对象(prototype)
4. 函数原型对象上的 隐式原型属性(__proto__)指向 Object对象
5. Object上的原型对象属性指向Object的原型对象(Object.prototype)
6. Object.prototype 上的隐式原型属性(__proto__)指向null
****************************************************************************************************************************************************/
原型链图解:
Person.prototype的指向改变之前
Person.prototype的指向改变之后: