面试官:如何判断一个对象是否为数组。
我:,说判断对象的constructor是否指向Array, 接着判断对应的特殊属性,如length,splice之类。(这里紧张了下,其实我最肯定会用instanceof判断的)
面试官:这些都是很容易冒充的。
我:那instanceof判断。
面试官:嗯,在平常应用中,这个是没问题的,但是在极端或者非常特殊的情况下会出现问题,你知道是什么吗?
我:如果对象继承数组的话,会出问题(这里没表述好,我的意思是这样的,function A(){}; A.prototype = [ ];).
面试官:(有些忘记说什么了)数组怎么可以被继承呢?(我想可能面试官也觉得自己没太理解我的意思=。=!当时我也没100%把握这样会导致intanceof失效)
我:(当时有点乱了貌似- -~~ ~~)那就不清楚了。
面试官:在平常应用的情况下,instanceof确实没问题,不过如果在页面有iframe的情况下就会出错了,即有个A页面定义了一个数组a,页面又嵌套了一个IFrame,在Iframe里面通过 top.a instanceof Array, 是返回false的。(各位去试试,我试了下,确实如此。。)。不过不要紧,这个确实太偏了。 那你知道有什么更好的方法判断数组么?
我:。。。。。。。
面试官:通过Object.prototype.toString.call(obj)这样就可以了,JQ源码也是这样写的。
我:额,这样会返回[Object Array].
==========================================
接下来的内容是分析下上面的题目,反正这次面试每题都长了见识了。水准确实不一样 = 。= !~
首先面试官给的方法肯定是可以的。这里主要是instanceof的问题。 其实除了面试说的那个特例,instanceof在以下几个情况下也是不行的,包括我的回答,以下给出一些instanceof会出错的情况: instanceof的原理见这篇文章:http://developer.51cto.com/art/201104/254421.htm
1、将构造函数的prototype指向Array的prototype:
function t(){};
t.prototype = Array.prototype
var x = new t();
alert(x instanceof Array);//弹出true
2、将构造函数的prototype指向一个实例化的数组:
function t(){};
t.prototype = [];
var x = new t();
alert(x instanceof Array);//弹出true
3、额外得到的一个结论:无法改变内置类型的prototype指向其他对象或null。 即从另一方面论证了通过调用Object.prototype.toString.call(obj)是行之有效的方法。
Array.prototype = {
splice:function(){alert(11)}
};
var arr = [];
alert(arr instanceof Array);//弹出true,说明与Array的内置原型对象的引用还是保存着的
alert(arr.splice)//弹出function splice(){ [native code]}; 说明上面的改变Array原型指向的代码失效,浏览器静默失败。
/*2011年10月24日更新*/
既然知道了instanceof的原理,那么面试官所说的 top.arr instanceof Array这个问题也自然知道什么原因了,Array实质是window.Array, 自然top.Array和IFRAME内的window.Array是不同的,所以会导致instanceof失效。如果top.arr instanceof top.Array 这样就没问题了。