日期:2014-05-16  浏览次数:20335 次

JavaScript的instanceof有bug?

前几天,又是工作上的问题。发现一个对象实例在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属性,用来判断实例的这个属性。当然这个不能解决别人已经创建的对象,或者已有框架,所以不是完美的解决办法。