我們假設要寫個isArray() 的方法,當然ecmascript5 已經添加了這個方法,(>ie8)
首先我們使用typeof:
在ECMAScript 中有5中基礎資料型別 (Elementary Data Type),Undefined、Null、Boolean、Number、String,還有一種複雜的資料類型,即:Object
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
MDN Description:All objects in JavaScript are descended from Object; all objects inherit methods and properties from Object.prototype, although they may be overridden
在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