我们假设要写个isArray() 的方法,当然ecmascript5 已经添加了这个方法,(>ie8)
首先我们使用typeof:
在ECMAScript 中有5中基本数据类型,Undefined、Null、Boolean、Number、String,还有一种复杂的数据类型,即:Object
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
在javascript中,Object是‘祖先‘,所有objects都是Object的子,并从Object.prototype下继承属性和方法。
使用typeof时要注意的就是typeof null = "object";
var arr=new Array();
typeof arr === "object";//true
显然只用typeof 是不行的,无论引用的是什么类型的对象,它都返回 "object"。然后我们就会想到instanceof或constructor
arr instanceof Array; // true
arr.constructor === Array; // true
但是在不同iframe下,就不行了!
var iframe = document.createElement(‘iframe‘);
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]
arr instanceof Array; // false
arr.constructor === Array; // false
MDN Description:Different scope have different execution environments. This means that they have different built-ins (different global object, different constructors, etc.).
下面具体解释!
先说constructor
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
MDN Description:All objects inherit a constructor property from their prototype。
所有的objects 都从它们的prototype继承了constructor属性。而这个constructor指向了这个object本身,也就是所谓的构造函数!即 Array.prototype.constructor === Array
所以上面的 arr.constructor === Array;
但是在不同iframe下,由于每个iframe都有一套自己的执行环境,不同的执行环境具有不同的原型链, 接着上面的代码,xArray.prototype === Array.prototype //false ,
所以上面的 arr.constructor !== Array;
再说下instanceof,这个有点复杂,耐心看!
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
MDN Description:The instanceof operator tests presence of constructor.prototype in object prototype chain.instanceof 用来判断 构造函数的原型是否存在于 某个object的原型链上
这句话翻译过来很难理解,说简单点,instanceof 用于判断一个变量是否是某个object的实例。
我们来看看instanceof 的原理,这样就会理解那句话了!
首先解释下原型,在 JavaScript 原型继承结构里面,规范中用 [[Prototype]] 表示对象隐式的原型,在 JavaScript 中用 __proto__ 表示,并且在 Firefox 和 Chrome 浏览器中是可以访问得到
这个属性的,但是 IE 下不行, 这个属性指向它的原型对象。在 JavaScript 里用 prototype 属性表示显示的原型,这个大家都知道;
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样一直找下去,你可以再Chrome下输入
一个对象,比如window,然后点开,在最下面就会看到__proto__,点开__proto__,最下面又有__proto__,这个就是javascript的原型链!
关于__proto__,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
让我们看下instance_of 的一段代码
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
var O = R.prototype;// 取 R 的显示原型,即构造函数的原型(这里说构造函数是配合上面的英文)
L = L.__proto__;// 取 L 的隐式原型
while (true) { //循环查找object的原型链
if (L === null)
return false;
if (O === L)// 构造函数的原型存在于 某个object的原型链上
return true;
L = L.__proto__; //继续查找
}
}
这段代码是一篇博客里copy的,应该是段伪代码!它很清楚的表达的instance_of的原理,也解释了上面的英文!
重新组织下语言,可以这样说: 如果‘类‘(构造函数)的原型与对象(object)原型链上的某一个原型是同一个对象,那么instanceof运算将返回true。
理解了原理,我们再回到上面的 var arr=new Array();
由于Array.prototype === arr.__proto__;//true
所以 arr instanceof Array; // true
在不同iframe下,arr instanceof Array; // false ,这个在constructor里已经解释了,即:不同的执行环境具有不同的原型链!
上面是借isArray来分析 typeof, instanceof and constructor 这三个东东!
但是isArray到底该怎么来实现的!查看了下jquery的源码,和mdn的大同小异!
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
主要原理是利用了Object.prototype.toString()https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
MDN Description:If this method is not overridden in a custom object, toString() returns "[object type]"
如果这个方法没有被重载的话,它会返回"[object type]",即可以得到对应的类型!(更详细的返回值可以通过http://www.ecma-international.org/ecma-262/5.1/或http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf来查看)
Object.prototype.toString()可以判断所有的内置类型,这里只是用Array举例而已!
看下面代码!
var isArray = function (vArg) {
return Object.prototype.toString.call(vArg) === "[object Array]";
};
call改变toString的this引用为待检测的对象,返回此对象的字符串表示,然后对比此字符串是否是‘[object Array]‘,以判断其是否是Array的实例。
也许你要问了,为什么不直接o.toString()?嗯,虽然Array继承自Object,也会有toString方法,但是这个方法已经被改写了!不能返回type;详情看https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString或上面的http://www.ecma-international.org/ecma-262/5.1
参考博客:
http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/ //instanceof
http://www.cnblogs.com/qiantuwuliang/archive/2011/01/08/1930548.html //constructor
http://blog.csdn.net/isea533/article/details/7248520 //isArray