這次主要說說javascript的類型判斷函數typeof和判斷構造函數原型instanceof的用法和注意的地方。
typeof
先來說說typeof吧。首先需要注意的是,typeof方法返回一個字符串,來表示數據的類型。
typeof 是一個一元運算,放在一個運算數之前,運算數可以是任意類型。
它返回值是一個字符串,該字符串說明運算數的類型。typeof 一般只能返回如下幾個結果:
number,boolean,string,function,object,undefined。我們可以使用 typeof 來獲取一個變量是否存在,如 if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因為如果 a 不存在(未聲明)則會出錯,對于 Array,Null 等特殊對象使用 typeof 一律返回 object,這正是 typeof 的局限性。
語法講解
我們先看看各個數據類型對應typeof的值:
| 數據類型 | Type |
|---|---|
| Undefined | “undefined” |
| Null | “object” |
| 布爾值 | “boolean” |
| 數值 | “number” |
| 字符串 | “string” |
| Symbol (ECMAScript 6 新增) | “symbol” |
| 宿主對象(JS環境提供的,比如瀏覽器) | Implementation-dependent |
| 函數對象 | “function” |
| 任何其他對象 | “object” |
再看看具體的實例:
// Numberstypeof 37 === 'number';typeof 3.14 === 'number';typeof Math.LN2 === 'number';typeof Infinity === 'number';typeof NaN === 'number'; // 盡管NaN是"Not-A-Number"的縮寫,意思是"不是一個數字"typeof Number(1) === 'number'; // 不要這樣使用!// Stringstypeof "" === 'string';typeof "bla" === 'string';typeof (typeof 1) === 'string'; // typeof返回的肯定是一個字符串typeof String("abc") === 'string'; // 不要這樣使用!// Booleanstypeof true === 'boolean';typeof false === 'boolean';typeof Boolean(true) === 'boolean'; // 不要這樣使用!// Symbolstypeof Symbol() === 'symbol';typeof Symbol('foo') === 'symbol';typeof Symbol.iterator === 'symbol';// Undefinedtypeof undefined === 'undefined';typeof blabla === 'undefined'; // 一個未定義的變量,或者一個定義了卻未賦初值的變量// Objectstypeof {a:1} === 'object';// 使用Array.isArray或者Object.prototype.toString.call方法可以從基本的對象中區分出數組類型typeof [1, 2, 4] === 'object';typeof new Date() === 'object';// 下面的容易令人迷惑,不要這樣使用!typeof new Boolean(true) === 'object';typeof new Number(1) ==== 'object';typeof new String("abc") === 'object';// 函數typeof function(){} === 'function';typeof Math.sin === 'function';我們會發現一個問題,就是typeof來判斷數據類型其實并不準確。比如數組、正則、日期、對象的typeof返回值都是object,這就會造成一些誤差。
所以在typeof判斷類型的基礎上,我們還需要利用Object.prototype.toString方法來進一步判斷數據類型。
我們來看看在相同數據類型的情況下,toString方法和typeof方法返回值的區別:
| 數據 | toString | typeof |
|---|---|---|
| “foo” | String | string |
| new String(“foo”) | String | object |
| new Number(1.2) | Number | object |
| true | Boolean | boolean |
| new Boolean(true) | Boolean | object |
| new Date() | Date | object |
| new Error() | Error | object |
| new Array(1, 2, 3) | Array | object |
| /abc/g | RegExp | object |
| new RegExp(“meow”) | RegExp | object |
可以看到利用toString方法可以正確區分出Array、Error、RegExp、Date等類型。
所以我們一般通過該方法來進行數據類型的驗證
真題檢測
但是既然今天說到了typeof,那這里就列出幾道題目,來看看自己是否真正掌握了typeof的用法。
第一題:
var y = 1, x = y = typeof x;x;
第二題:
(function f(f){return typeof f();})(function(){ return 1; });第三題:
var foo = {bar: function() { return this.baz; },baz: 1};(function(){return typeof arguments[0]();})(foo.bar);第四題:
var foo = {bar: function(){ return this.baz; },baz: 1}typeof (f = foo.bar)();第五題:
var f = (function f(){ return "1"; }, function g(){ return 2; })();typeof f;第六題:
var x = 1;if (function f(){}) {x += typeof f;}x;第七題:
(function(foo){return typeof foo.bar;})({ foo: { bar: 1 } });下面公布答案了,這七題的答案分別是:
"undefined","number","undefined","undefined","number","1undefined","undefined"
做對了幾道呢?是不是很大的困惑呢?這幾題雖然都有typeof,但是考察了很多javascript的基礎噢。下面我們來一一詳解。
第一題:
var y = 1, x = y = typeof x;x;//"undefined"
表達式是從右往左的,x由于變量提升,類型不是null,而是undefined,所以x=y=”undefined”。
變量提升我在這篇文章中提到過,可以看看。
第二題:
(function f(f){return typeof f();//"number"})(function(){ return 1; });傳入的參數為f也就是function(){ return 1; }這個函數。通過f()執行后,得到結果1,所以typeof 1返回”number”。這道題很簡單,主要是區分f和f()。
第三題:
var foo = {bar: function() { return this.baz; },baz: 1};(function(){return typeof arguments[0]();//"undefined"})(foo.bar);這一題考察的是this的指向。this永遠指向函數執行時的上下文,而不是定義時的(ES6的箭頭函數不算)。當arguments執行時,this已經指向了window對象。所以是”undefined”。對this執行不熟悉的同學可以看看這篇文章:深入理解this,對剛剛提到的箭頭函數感興趣的同學可以看看初步探究ES6之箭頭函數。
第四題:
var foo = {bar: function(){ return this.baz; },baz: 1}typeof (f = foo.bar)();//undefined如果上面那一題做對了,那么這一題也應該不會錯,同樣是this的指向問題。
第五題:
var f = (function f(){ return "1"; }, function g(){ return 2; })();typeof f;//"number"這一題比較容易錯,因為我在遇到這道題之前也從來沒有遇到過javascript的分組選擇符。什么叫做分組選擇符呢?舉一個例子就會明白了:
var a = (1,2,3);document.write(a);//3,會以最后一個為準
所以上面的題目會返回2,typeof 2當然是”number”啦。
第六題:
var x = 1;if (function f(){}) {x += typeof f;}x;//"1undefined"這是一個javascript語言規范上的問題,在條件判斷中加入函數聲明。這個聲明語句本身沒有錯,也會返回true,但是javascript引擎在搜索的時候卻找不到該函數。所以結果為”1undefined”。
第七題:
(function(foo){return typeof foo.bar;})({ foo: { bar: 1 } });這題其實是一個考察心細程度的題目。形參的foo指向的是{ foo: { bar: 1 } }這個整體。相信這么說就明白了。
好啦。上面的題目都是很好的資源噢。
instanceof
接下來該說說instanceof方法了。instanceof運算符可以用來判斷某個構造函數的prototype屬性是否存在于另外一個要檢測對象的原型鏈上。
instanceof 用于判斷一個變量是否某個對象的實例,如 var a=new Array();alert(a instanceof Array); 會返回 true,同時 alert(a instanceof Object) 也會返回 true;這是因為 Array 是 object 的子類。再如:function test(){};var a=new test();alert(a instanceof test) 會返回
談到 instanceof 我們要多插入一個問題,就是 function 的 arguments,我們大家也許都認為 arguments 是一個 Array,但如果使用 instaceof 去測試會發現 arguments 不是一個 Array 對象,盡管看起來很像。
如果對原型不太了解,可以看看深入理解原型。
下面我們看看instanceof的實例:
// 定義構造函數function C(){} function D(){} var o = new C();// true,因為 Object.getPrototypeOf(o) === C.prototypeo instanceof C; // false,因為 D.prototype不在o的原型鏈上o instanceof D; o instanceof Object; // true,因為Object.prototype.isPrototypeOf(o)返回trueC.prototype instanceof Object // true,同上C.prototype = {};var o2 = new C();o2 instanceof C; // trueo instanceof C; // false,C.prototype指向了一個空對象,這個空對象不在o的原型鏈上.D.prototype = new C(); // 繼承var o3 = new D();o3 instanceof D; // trueo3 instanceof C; // true但是這里我們需要注意一個問題:
function f(){ return f; }document.write(new f() instanceof f);//falsefunction g(){}document.write(new g() instanceof g);//true第一個為什么返回false呢?因為構造函數的原型被覆蓋了,我們可以看看new f和new g的區別:

新聞熱點
疑難解答