Javascript中instanceof运算及constructor属性

事先申明:看懂此文需要对javascript中原型的概念有所了解。 

上代码

 1  //构造函数animal
 2     function animal() {
 3         this.move = function () {
 4             return 'move';
 5         }
 6     }
 7 
 8     //1个空(函数体空)函数
 9     function emptyFunc() { }
10     //空函数原型指向animal原型
11     emptyFunc.prototype = animal.prototype;
12     var a = new emptyFunc();//字面上a的构造器指向emptyFunc,但由于上面那句话 a的构造器应该指向animal
13 
14 
15     alert(a.constructor == animal);//true 验证了上句注释
16     alert(a instanceof animal);//true,a的构造器指向animal,我的理解: a其实是由构造器 animal new操作得到的。所以是true。
17     alert(a instanceof emptyFunc);//true: 理解不下去了。产生疑问:a到底是那个构造器构造的?继承啦?
18     alert(a.constructor == emptyFunc);//false 

 

疑问:如果a是由animal构造,为啥访问不了animal的实例方法 move,如果是由emptyFuc构造 为啥a的构造器指向的是animal ?

为什么要有这样的代码?是因为看了阮一峰的文章 Javascript面向对象编程(二):构造函数的继承 中第四部分 “利用空对象作为中介” 来实现继承,本想来学习一下这个继承方式,但是百思不得其

解。以至于上面的代码并未完成一个完整继承。如果希望看到完整的继承方式及其他更多的继承方式,完全可以参考阮一峰的Javascript面向对象编程的3篇文章。

Javascript 面向对象编程(一):封装

Javascript面向对象编程(二):构造函数的继承

Javascript面向对象编程(三):非构造函数的继承

 

实例a的构造器指向谁了,由谁构造 ?

行12由emptyFunc构造器来构造实例a,但由于行11,导致了a的构造器指向了animal。理由如下:

1.每个构造器都有一个原型对象prototype,该原型对象有一个constructor属性指向构造器本身,由于javascript的原型继承的机制,所有实例必然会从构造器的原型对象中继承到原型里所有属性,所以

每一个实例必然会有一个constructor属性,这个属性是来源于构造器的原型对象,并不是真正(hasOwnProperty)拥有该属性。

2.每个实例都有一个隐藏的属性__proto__,在FF和Chrome可以看的到该属性,该属性指向构造器的原型对象,js中的原型继承,就是基于此原型对象来实现的。

实例的隐藏__proto__从哪里来的,可以参见 再谈javascript面向对象编程

var a = new emptyFunc() : a由emptyFunc构造,且a.__proto__ == empntyFunc.prototype(实例a的原型对象__proto__指向构造器的原型对象);

emptyFunc.prototype = A.prototype: 结合上一句代码,其实就造成了a.__proto__ == empntyFunc.prototype == Animal.prototype;

根据1,我们知道a.contructor == a.__proto__.constuctor == Animal.prototype.constructor == Animal;

所以说 行15是true。需要注意的是,虽然a的构造器指向了animal,但是a不是由animal构造的。而是由new操作来决定的。这正好解释了a为什么不能访问方法move, move方法是A的实例

法,并不处在a的原型链上。

 

instanceof到底用来做什么呢?

a instanceof A: 含义是判断a原型链上的原型对象是否指向A.prototype. 口语理解就是 a是不是A类型的实例,不是用来判定a是不是由A来构造。 大概过程是这样的。

var O = animal.prototype;

var V;

while(V=a.__proto__){

  if(V==null)return false;
  if(O==V)return true;
  a = a.__proto__

 }

所以:

alert(a instanceof emptyFunc) 
alert(a instanceof animal); 

通过上面的分析,很显然,这两个在while在第一次循环时就返回true 当然  a instanceof Object 也是True啦。

 

我想,现在大家对一开始提出的疑问有了自己的答案。

也许你要问为什么instanceof是做如此运算及object创建过程如再谈javascript面向对象编程文中谈论的一样,你可以参见ECMAScript的第5版规范 里面的关于instanceof和new运算的描述。

也许你还要问为什么要去理解这些东西,因为我觉得由instaceof和constructor引来的疑问,从另一个侧面让我更加深刻的理解了javascript中的原型继承的玩法。

关于此问题的全部讨论,你可以在新浪微博看到全貌http://weibo.com/1834525061/zwIM6wjbx#_rnd1368846568618

 全部讨论截图:

 

 

国际惯例:严重感谢新浪微博网友@aimingoo @朴灵 @第11建筑中队 @低级码畜 @寒冬winter  @貘吃馍香 等等

 

 

posted @ 2013-05-18 11:23  wind hong  阅读(742)  评论(1编辑  收藏  举报