javaScritp 中prototype属性继承原理详解

         转载请说明出处:http://blog.csdn.net/liuqiwen0512/article/details/8095306

             上一篇文章我们说了jQuery  运用jQuery.fn.init.prototype = jQuery.fn;巧妙的避开了 instanceof 的运算。

       要解释这个问题就需要先了解prototype属性的继承原理,比如toString方法,我们创建一个对象不用给对象

       添加toString方法照样可以用。这是为什么,是创建对象的时候js自动给对象添加了toString方法,还是通过上面途径

       找到了toString方法。这里可以告诉你我们用new关键字创建出来的对象要是你没给它添加toString属性的话,

       那么它调用的就是Object对象的prototype.toString。这是为什么,有的童鞋说是继承,但是它又是怎样继承的,

       toString到底放在哪,看完这篇文章你就明白了。还有一个问题就是instanceof运算符到底是怎么运算的,

       它的依据和原理是什么,同样看完这篇文章你也就明白了。

 

protype继承原理:

             其实我们用function关键字声明的方法,在后台js会把他们创建成Function对象。这个对象中有两个属性,一个是prototype

             这个属性是显式属性也就是说我们可以访问的属性。还有一个属性就是__proto__这个属性是隐式的,也就是说默认

             情况下我们不可以访问,而且这个属性在个浏览器的表示可能还不一致,默认情况下是__proto__。这个属性在chrome

             浏览器是可以访问的,但是在IE下就不可以访问,不知道是IE不让访问,还是表示不一样,没研究。

             prototype属性是一个指针,指向一个实例化的Object对象。这个对象默认有两个属性,一个是显式属性constructor,

             这个属性是指向prototype属性所在的构造函数,这样prototype属性所指向的Object对象和构造函数就形成了循环

             指向。还有一个隐式属性默认是__proto__指向它的父对象也就是js内置的Object对象的prototype属性所指向的

             一个实例化的Object对象。

 

下面看例子说话:

[javascript] view plain copy
 
 print?
  1. function Person(){  
  2.       this.name="刘奇文";  
  3.       this.age=22;  
  4. }  
  5.     Person.prototype={  
  6.            showName:function(){  
  7.               console.log(this.name);  
  8.            },  
  9.            name:"liuqiwen"  
  10.     }  
  11. function Man(){  
  12.       this.name="刘奇文man";  
  13.       this.age=22;  
  14. }  
  15.     Man.prototype=Person.prototype;  
  16.   
  17. var man1=new Man();  
  18. console.log(man1.name);//结果:刘奇文man  
  19. man1.showName();//结果:刘奇文man  
  20. delete man1.name;//删除实例中的name属性  
  21. console.log(man1.name);//结果:liuqiwen  
  22. man1.showName();//结果:liuqiwen  
  23. console.log(man1.constructor);//结果:function Object() {[native code]}  
  24. console.log(man1 instanceof Man);//结果:true  
  25. console.log(man1 instanceof Person);//结果:true  
  26. console.log(man1 instanceof Object);//结果:true  

上面代码解释:

             创建一个构造函数Person,给构造函数添加两个属性。然后再初始化构造函数的原型链prototype属性,

       给prototype添加两个属性,在创建一个构造函数Man,给构造函数添加两个属性。然后再初始化 构造函数

      的原型链prototype属性,让prototype属性等于Person的prototype属性,也就是说这两个构造函数的prototype

      指向的是同一个Object对象。然后创建一个man1的一个实例,调用man1的name属性得到结果正是实例中

      属性的值,调用man1的showName方法得到也是实例中属性值结果都正确,我们再删除实例中name属性

      我们再重复上面的操作发现结果是原型链中属性的值,我们再调用man1的constructor属性,这个属性

      上面已经说过是得到这个实例的构造函数的引用,上面我们既没有给实例定义这个属性,原型链中也

      没有这个属性,那么调用这个属性得到的值是哪里来的,为什么还是Object。

对象属性的查找顺序:

             其实我们没有给prototype属性赋值时,prototype属性默认指向的Object对象是有

      constructor这个属性的,由于这个属性是显式的是我们可控制的,所以当我们给prototype属性初始化

      时是让它指向了另一个对象,而这个对象中没有此属性,我们也可加上这个属性。当对象在实例中

      没有找到要调用的属性,那么他会从他的隐式属性__proto__所指向的原型链中查找,如果还没找到,

       那么他会继续查找原型链中的隐式__proto__属性所指向的对象,

      也就是实例的父对象Object对象的原型链,所以返回值是Object的构造函数。

总结:实例对象属性查找顺序是   实例对象内部---->构造函数原型链---->实例对象父对象的原型链。

 

instanceof运算符:

        上面man1 instanceof Man结果为true,运算符先运算Man.prototype然后再查找man1中的__proto__

        所指向的Object是否为Man.prototype。由于Person.prototype和Man.prototype指向的是同一个Object

        所以man1 instanceof Person结果为true。man1 instanceof Object由于man1中的__proto__指向的

        不是Object.prototype所以运算符会继续查找__proto__指向的对象中的__proto__属性,也就是实例

         父对象的prototype指向的对象,Object是实例man1的父对象所以运算结果为true。

 

通过关系图来了解他们之间的关系

继承关系图:

 下篇分析下构造函数和Object之间的关系 ,js内置对象之间的关系。

上图中 Function 和 Object之间的关系有些地方好像不太对,

还需研究,如果哪位仁兄知道的话,请赐教。

 转载请说明出处:http://blog.csdn.net/liuqiwen0512/article/details/8095306

posted @ 2016-02-25 17:28  时光 说:  阅读(454)  评论(0编辑  收藏  举报