前几天,又是工作上的问题。发现一个对象实例在instanceof XXX的时候,竟然返回了false,看看对象的内部结构,明明跟XXX的内部定义一样的。于是乎开始怀疑instanceof是不是有bug了,因为之前在创建一数组,在调了一圈之后,instaceof Array竟然也是false。不过后来阿飞调试之后,发现完全是因为跨页面传递了对象导致的。。。现将问题重现一下:
1、创建一个页面outer.html,并添加一个iframe
<iframe align="center" border="1" width="70%" title="Woo~" height="50%" src="bottom.html" name="bottom">aha~</iframe>
2、创建bottom.html页面
3、 添加outer.js文件,用来获取frame里边的页面,获取界面hanlder实例,并向其中传递数据
Ext.onReady(function() { var btmHandler; var fn = function() { btmHandler = window.frames["bottom"].document.handler; if (!btmHandler) { //iframe里边的页面还没有初始化完毕,就轮询,直到里边的页面装载完毕 setTimeout(fn, 300); } else { //store instanceof Ext.data.Store: false var value1 = "({nickname:'maitian',store:new Ext.data.ArrayStore()});" btmHandler.accept(eval(value1)); btmHandler.showInfo(); //store instanceof Ext.data.Store: true var value2 = "{nickname:'maitian',store:new Ext.data.ArrayStore()}" btmHandler.accept(value2); btmHandler.showInfo(); } }; fn(); });
4、为bottom.html创建 相应的js文件,并添加相关代码:
function BottomHandler() { this.name = 'Bottom'; this.data = {}; }; BottomHandler.prototype = { constructor : BottomHandler, accept : function(value) { if (Ext.isString(value)) { value = eval('(' + value + ');'); } if (Ext.isObject(value)) { Ext.apply(this.data, value) } }, showInfo : function() { alert("store instanceof Ext.data.Store: " + (this.data.store instanceof Ext.data.Store)); } }; Ext.onReady(function() { var hanlder = document.getHandler(); }); document.getHandler = function() { if (!document.handler) { document.handler = new BottomHandler(); } return document.handler; };
5、创建完后,运行,会发现两个弹出框的结果,一个为false,一个为true。instanceof的内部机制是:每个实例都有__proto__隐藏属性,instanceof的时候会拿实例的__proto__属性与构造函数的prototype比较是否相同,如果一个对象是在A页面创建的,然后拿到B页面上,判断是不是某个构造函数的实例,就会发现返回false,因为prototype本质上也是一个Object,不同js虚拟机上创建的两个对象,怎么也不可能相同的。
6、解决办法:
a、像本例一样,跨页面传递数据的时候,只传字符串,传过去后再eval
b、像Ext.isArray实现一样,判断对应的字符串是否相等(Object.prototype.toString.call(inst) == '[object Array]'),但是对于所有自定义的构造函数的实例,都返回的是"[object Object]"。所以只有为没个自定义的构造函数都创建一个clazzType属性,用来判断实例的这个属性。当然这个不能解决别人已经创建的对象,或者已有框架,所以不是完美的解决办法。