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篇文章。
实例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 @貘吃馍香 等等