資料型態的判斷有這麼多種方式
1、一元運算子 typeOf
2、關係運算子 instanceof
3、constructor 屬性
4、prototype屬性
一、typeof
typeof的回傳值有以下幾種
類型 | 結構 |
---|---|
Undefined | "undefined" |
Null |
"object" (見下方) |
布林值 | "boolean" |
數值 | "number" |
字串 | "string" |
Symbol (ECMAScript 6 新增) | "symbol" |
宿主物件(JS環境提供的,如瀏覽器) | Implementation-dependent |
函數物件 (implements [[Call]] in ECMA-262 terms) | "function" |
任何其他物件 | "object" |
簡單粗暴的方法,直接看程式碼
// 以下代码在版本 Google Chrome 45.0.2454.101 m 中测试通过 // Numbers console.log(typeof 37 === 'number'); console.log(typeof 3.14 === 'number'); console.log(typeof Math.LN2 === 'number'); console.log(typeof Infinity === 'number'); console.log(typeof NaN === 'number'); // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字" console.log(typeof Number(1) === 'number'); // 不要这样使用! // Strings console.log(typeof "" === 'string'); console.log(typeof "bla" === 'string'); console.log(typeof (typeof 1) === 'string'); // console.log(typeof返回的肯定是一个字符串 console.log(typeof String("abc") === 'string'); // 不要这样使用! // Booleans console.log(typeof true === 'boolean'); console.log(typeof false === 'boolean'); console.log(typeof Boolean(true) === 'boolean'); // 不要这样使用! // Symbols console.log(typeof Symbol() === 'symbol'); console.log(typeof Symbol('foo') === 'symbol'); console.log(typeof Symbol.iterator === 'symbol'); // Undefined console.log(typeof undefined === 'undefined'); console.log(typeof blabla === 'undefined'); // 一个未定义的变量,或者一个定义了却未赋初值的变量 // Objects 使用Array.isArray或者Object.prototype.toString.call方法可以从基本的对象中区分出数组类型 console.log(typeof {a:1} === 'object'); console.log(typeof [1, 2, 4] === 'object'); console.log(typeof /^[a-zA-Z]{5,20}$/ === 'object'); console.log(typeof {name:'wenzi', age:25} === 'object'); console.log(typeof null === 'object');//true // 下面的容易令人迷惑,不要这样使用! console.log(typeof new Boolean(true) === 'object'); console.log(typeof new Number(1) === 'object'); console.log(typeof new Date() === 'object'); console.log(typeof new String("abc") === 'object'); console.log(typeof new Error() === 'object'); // 函数 console.log(typeof function(){} === 'function'); console.log(typeof Math.sin === 'function');
typeof 只能檢查出來以上7幾種類型
二、instanceof
instanceof 運算子用於識別正在處理的物件的類型,要求開發者明確地確認物件為某特定類型
1、instanceof 和 constructor 沒有關係
var A = function() {}; A.prototype = {}; var B = {}; console.log(A.constructor);//function Function() { [native code] } console.log(B.constructor);//function Object() { [native code] } var a = new A(); A.prototype = {}; var b = new A(); b.constructor = A.constructor; console.log(a.constructor === A);//false console.log(a.constructor);//function Object() { [native code] } console.log(typeof A);//function Object() { [native code] } console.log(a.constructor === b.constructor);//false console.log(b.constructor);//function Function() { [native code] } console.log(a instanceof A);//false console.log(b instanceof A);//true
2、instanceof又叫關係運算符,可以用來判斷某個建構子的prototype屬性是否存在另外一個要偵測物件的原型鏈上
var str = new String("hello world"); console.log(str instanceof String);//true console.log(String instanceof Function);//true console.log(str instanceof Function);//false
第三次輸出為什麼會回傳false呢 ?原文網址:Javascript中一個關於instanceof的問題
//表达式一的指向 console.log(str.__proto__ === String.prototype);//true console.log(str instanceof String); //true //表达式二的指向 console.log(String .__proto__ === Function.prototype);//true console.log(String instanceof Function);//true //表达式三的指向 console.log(str .__proto__ === String.prototype);//true console.log(str .__proto__.__proto__ === String.prototype.__proto__);//true console.log(str .__proto__.__proto__ === Object.prototype);//true console.log(str .__proto__.__proto__.__proto__ === null);//true console.log(str instanceof Object);//true console.log(str instanceof Function);//false
再看一個複雜的用法
console.log(Object instanceof Object);//true console.log(Function instanceof Function);//true console.log(Number instanceof Number);//false console.log(String instanceof String);//false console.log(Function instanceof Object);//true console.log(Foo instanceof Function);//true console.log(Foo instanceof Foo);//false
為什麼,這是為什麼呢,要搞清楚以下意義
1、語言規範中是如何定義這個運算子的
2、JavaScript 原型繼承機制
Object instanceof Object
// 为了方便表述,首先区分左侧表达式和右侧表达式 ObjectL = Object, ObjectR = Object; console.log(ObjectL instanceof ObjectR);//true
// 下面根据规范逐步推演 console.log(ObjectL.__proto__ === Function.prototype); //true console.log(ObjectL.__proto__.__proto__ === Object.prototype);//true
Function instanceof Function
FunctionL = Function, FunctionR = Function; console.log(FunctionL instanceof FunctionR);//true console.log(FunctionL.__proto__ === Function.prototype); //true <strong>Foo instanceof Foo </strong> function Foo(){} var foo = new Foo(); FooL = Foo, FooR = Foo; console.log(FooL instanceof FooR);//false console.log(FooL.__proto__ === Function.prototype );//true console.log(FooL.__proto__.__proto__ === Object.prototype );//true console.log(FooL.__proto__.__proto__.__proto__ === null );//true
instanceof 在 Dojo 繼承機制中的應用
在 JavaScript 中,是沒有多重繼承這個概念的,就像 Java 一樣。但在 Dojo 中使用 declare 宣告類別時,是允許繼承自多個類別的
dojo.declare("Aoo",null,{}); dojo.declare("Boo",null,{}); dojo.declare("Foo",[Aoo,Boo],{}); var foo = new Foo(); console.log(foo instanceof Aoo);//true console.log(foo instanceof Boo);//false console.log(foo.isInstanceOf(Aoo));//true console.log(foo.isInstanceOf(Boo));//true
instanceof和多全域物件(多個frame或多個window之間的交互作用)
在瀏覽器中,我們的腳本可能需要在多個視窗之間進行互動。多個視窗意味著多個全域環境,不同的全域環境擁有不同的全域對象,從而擁有不同的內建類型建構函數。這可能會引發一些問題。例如,表達式[] instanceof window.frames[0].Array 會回傳false,因為Array.prototype !== window.frames[0].Array.prototype,因此你必須使用Array.isArray(myObj) 或者Object. prototype.toString.call(myObj) === "[object Array]"來判斷myObj是否為陣列。
// 以下代码在版本 Google Chrome 45.0.2454.101 m 中测试通过 // Numbers console.log(37 instanceof Number);//false console.log( 3.14 instanceof Number);.//false console.log( Math.LN2 instanceof Number);//false console.log( Infinity instanceof Number);//false console.log( NaN instanceof Number); // false尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字" console.log( Number(1) instanceof Number); // false不要这样使用! // Strings console.log( "" instanceof String);// false console.log( "bla" instanceof String);// false console.log( ( 1) instanceof String); // falseconsole.log(返回的肯定是一个字符串 console.log( String("abc") instanceof String); // false 不要这样使用! // Booleans console.log( true instanceof Boolean);// false console.log( false instanceof Boolean);// false console.log( Boolean(true) instanceof Boolean); //false 不要这样使用! // Symbols console.log( Symbol() instanceof Symbol);// false console.log( Symbol("foo") instanceof Symbol);// false console.log( Symbol.iterator instanceof Symbol);// false // Undefined var blabla; //console.log( undefined instanceof Undefined);// Uncaught ReferenceError: Undefined is not defined //console.log( blabla instanceof Undefined); // Uncaught ReferenceError: Undefined is not defined console.log( undefined instanceof Object);// false console.log( blabla instanceof Object);// false // Objects 使用Array.isArray或者Object.prototype.toString.call方法可以从基本的对象中区分出数组类型 console.log( {a:1} instanceof Object);//true console.log( [1, 2, 4] instanceof Object);//true console.log( /^[a-zA-Z]{5,20}$/ instanceof Object);//true console.log( {name:'wenzi', age:25} instanceof Object);//true console.log( null === Object);//false // 下面的容易令人迷惑,不要这样使用! console.log( new Boolean(true) instanceof Object);//true console.log( new Number(1) instanceof Object);//true console.log( new Date() instanceof Object);//true console.log( new String("abc") instanceof Object);//true console.log( new Error() instanceof Object);//true // 函数 console.log( function(){} instanceof Function );//true console.log( Math.sin instanceof Function);//true
注意:undefined和null是偵測的Object類型,因為js中沒有Undefined和Null的這種全域類型,number, string和boolean無法偵測出它的類型
三、constructor
在使用instanceof檢測變數類型時,我們是偵測不到number, 'string', bool的類型的。因此,我們需要換個方式來解決這個問題
Object.prototype.constructor傳回一個指向建立了該物件原型的函數參考。需要注意的是,該屬性的值是那個函數本身,而不是一個包含函數名稱的字串。對於原始值(如1,true 或 "test"),該屬性為唯讀,所有物件都會從它的原型上繼承一個 constructor 屬性
constructor本來是原型物件上的屬性,指向建構子。但根據實例物件尋找屬性的順序,若實例物件上沒有實例屬性或方法時,就去原型鏈上尋找,因此,實例物件也是能使用constructor屬性的
function Person(){ } var Tom = new Person(); console.log(Tom.constructor === Person);//true
不過要注意,constructor屬性是可以被修改的,會導致檢測出的結果不正確
function Person(){ } function Student(){ } Student.prototype = new Person(); var John = new Student(); console.log(John.constructor==Student); // false console.log(John.constructor==Person); // true
改變這個物件的constructor屬性的值
function Type() { }; var types = [ new Array, [], new Boolean, true, // remains unchanged new Date, new Error, new Function, function(){}, Math, new Number, 1, // remains unchanged new Object, {}, new RegExp, /(?:)/, new String, "test" // remains unchanged ]; for(var i = 0; i < types.length; i++) { types[i].constructor = Type; types[i] = [ types[i].constructor, types[i] instanceof Type, types[i].toString() ]; }; console.log( types.join("\n") );
除了undefined和null,其他類型的變數均能使用constructor判斷類型
四、萬能的Object.prototype.toString.call
使用toString()方法偵測物件類型
function Type() { }; var toString = Object.prototype.toString; console.log(toString.call(new Date) === '[object Date]');//true console.log(toString.call(new String) ==='[object String]');//true console.log(toString.call(new Function) ==='[object Function]');//true console.log(toString.call(Type) ==='[object Function]');//true console.log(toString.call('str') ==='[object String]');//true console.log(toString.call(Math) === '[object Math]');//true console.log(toString.call(true) ==='[object Boolean]');//true console.log(toString.call(/^[a-zA-Z]{5,20}$/) ==='[object RegExp]');//true console.log(toString.call({name:'wenzi', age:25}) ==='[object Object]');//true console.log(toString.call([1, 2, 3, 4]) ==='[object Array]');//true //Since JavaScript 1.8.5 console.log(toString.call(undefined) === '[object Undefined]');//true console.log(toString.call(null) === '[object Null]');//true
附上判斷函數 Javascript中的資料型別知多少
五、jquery的實作 jquery: "1.8.2",
jquery中提供了一個$.type的接口,看看代碼
var m = Object.prototype.toString //501行 E = {};//512行 isFunction: function(a) { //645行 return p.type(a) === "function" }, isArray: Array.isArray || function(a) { return p.type(a) === "array" } , isWindow: function(a) { return a != null && a == a.window }, isNumeric: function(a) { return !isNaN(parseFloat(a)) && isFinite(a) }, type: function(a) { return a == null ? String(a) : E[m.call(a)] || "object" }, isPlainObject: function(a) { if (!a || p.type(a) !== "object" || a.nodeType || p.isWindow(a)) return !1; try { if (a.constructor && !n.call(a, "constructor") && !n.call(a.constructor.prototype, "isPrototypeOf")) return !1 } catch (c) { return !1 } var d; for (d in a) ; return d === b || n.call(a, d) }, isEmptyObject: function(a) { var b; for (b in a) return !1; return !0 },
可以看出來,jquery中就是用Object.prototype.toString.call實作的