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对象。
下面看例子说话:
- function Person(){
- this.name="刘奇文";
- this.age=22;
- }
- Person.prototype={
- showName:function(){
- console.log(this.name);
- },
- name:"liuqiwen"
- }
- function Man(){
- this.name="刘奇文man";
- this.age=22;
- }
- Man.prototype=Person.prototype;
- var man1=new Man();
- console.log(man1.name);//结果:刘奇文man
- man1.showName();//结果:刘奇文man
- delete man1.name;//删除实例中的name属性
- console.log(man1.name);//结果:liuqiwen
- man1.showName();//结果:liuqiwen
- console.log(man1.constructor);//结果:function Object() {[native code]}
- console.log(man1 instanceof Man);//结果:true
- console.log(man1 instanceof Person);//结果:true
- 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