摘要:用對(duì)象字面量創(chuàng)建的對(duì)象會(huì)報(bào)錯(cuò),使用構(gòu)造函數(shù)創(chuàng)建的對(duì)象屬于。發(fā)現(xiàn),構(gòu)造函數(shù)創(chuàng)建的,,,,。從原型鏈角度講,構(gòu)造函數(shù)就是新對(duì)象的的類型。
一、前言
類型判斷有時(shí)候真的頭疼,但是一旦熟練使用就會(huì)覺(jué)得不過(guò)如此。初級(jí)的,會(huì)判斷數(shù)字和字符串。中級(jí)的,會(huì)判斷數(shù)組和對(duì)象。進(jìn)階的,會(huì)判斷日期,正則,錯(cuò)誤類型。高級(jí)的,會(huì)判斷plainObject,空對(duì)象,window對(duì)象等等。
基本類型:String、Number、Boolean、Symbol、Undefined、Null引用類型:Object
基本類型也稱為簡(jiǎn)單類型,由于其占據(jù)空間固定,是簡(jiǎn)單的數(shù)據(jù)段,為了便于提升變量查詢速度,將其存儲(chǔ)在棧中,即按值訪問(wèn)。
引用類型也稱為復(fù)雜類型,由于其值的大小會(huì)改變,所以不能將其存放在棧中,否則會(huì)降低變量查詢速度,因此,其值存儲(chǔ)在堆(heap)中,而存儲(chǔ)在變量處的值,是一個(gè)指針,指向存儲(chǔ)對(duì)象的內(nèi)存處,即按址訪問(wèn)。引用類型除 Object 外,還包括 Function 、Array、RegExp、Date 等等。
鑒于 ECMAScript 是松散類型的,因此需要有一種手段來(lái)檢測(cè)給定變量的數(shù)據(jù)類型。對(duì)于這個(gè)問(wèn)題,JavaScript 也提供了多種方法,但遺憾的是,不同的方法得到的結(jié)果參差不齊。
二、typeoftypeof是最經(jīng)常用到的判斷類型的。
typeof("saucxs") //"string" typeof "saucxs" //"string" typeof function(){console.log("saucxs")} //"function" typeof ["saucxs","songEagle",1,2,"a"] //"object" typeof {name: "saucxs"} //"object" typeof 1 //"number" typeof undefined //"undefined" typeof null //"object" typeof /^d/ //"object" typeof Symbol // "function"
其實(shí),typeof是一個(gè)運(yùn)算符,和加減乘除類似,這就是為啥可以這樣寫(xiě) typeof "saucxs"。
在《JavaScript權(quán)威指南》中對(duì)typeof的介紹:typeof是一元操作符,放在單個(gè)操作數(shù)的前面,操作數(shù)可以是任意類型。返回值表示操作數(shù)的類型的一個(gè)字符串。
JavaScript中一共有6中基本數(shù)據(jù)類型:string,number,boolean,null,undefined,symbol,一種對(duì)象類型:object。
分別對(duì)應(yīng)的typeof的值,結(jié)果不是一一對(duì)應(yīng)的,分別:string,number,boolean,object,undefined,function,對(duì)象類型:object。
注意:typeof 可以檢測(cè)函數(shù)類型
但是在object下還有很多細(xì)分內(nèi)部屬性:Array,F(xiàn)unction,Date,RegExp,Error等。
var date = new Date(); var error = new Error(); console.log(typeof date); // object console.log(typeof error); // object
所以還需要更好的區(qū)分。
三、instanceof使用instanceof的前提條件:object instanceof constructor。object--要檢測(cè)的對(duì)象。constructor--某個(gè)構(gòu)造函數(shù)。說(shuō)明使用這個(gè)instanceof必須是用來(lái)檢測(cè)對(duì)象的的類型,不能檢測(cè)其他類型。
A instanceof B用來(lái)判斷A是否為B的實(shí)例。如果A是B的實(shí)例,則返回true,否則false。
原理:instanceof是檢測(cè)原型。
instanceof (a,B) = { var l = a.__proto__; var R = B.prototype; if(l === R) { // a的內(nèi)部屬性 __proto__ 指向 B 的原型對(duì)象 return true; } return false; }
分析:a的_proto_指向B的prototype時(shí),a就是B的實(shí)例。
[] instanceof Array //true [] instanceof Object //true new Array([1,43,6]) instanceof Array // true new Array([1,43,6]) instanceof Object // true {} instanceof Object // 原型上沒(méi)有定義 Uncaught SyntaxError: Unexpected token instanceof ({}) instanceof Object; //true Object.create({"name": "saucxs"}) instanceof Object //true Object.create(null) instanceof Object //false 一種創(chuàng)建對(duì)象的方法,這種方法創(chuàng)建的對(duì)象不是Object的一個(gè)實(shí)例 new Date() instanceof Date //true new Date() instanceof Object //true "saucxs" instanceof Object //false "saucxs" instanceof String //false new String("saucxs") instanceof Object //true new String("saucxs") instanceof String //true 1 instanceof Object //false 1 instanceof Number //false new Number(1) instanceof Object //true new Number(1) instanceof Number //true true instanceof Object //false true instanceof Boolean //false new Boolean(true) instanceof Object //true new Boolean(true) instanceof Boolean //true null instanceof Object //false undefined instanceof Object //false Symbol() instanceof Symbol //false
注意:1、new Date對(duì)象既屬于Object,又屬于Date。(他們是由Object類派生出來(lái)的)。
2、用字面量創(chuàng)建的數(shù)組或者構(gòu)造函數(shù)創(chuàng)建的數(shù)組,既屬于Object,又屬于Array。
3、用對(duì)象字面量創(chuàng)建的對(duì)象object 會(huì)報(bào)錯(cuò), {} instanceof Object;使用構(gòu)造函數(shù)創(chuàng)建的對(duì)象屬于Object。
4、用字面量的創(chuàng)建的字符串,數(shù)字,布爾,既不屬于Object,也不屬于各自類型;只有使用構(gòu)造函數(shù)創(chuàng)建的字符串,數(shù)字,布爾,既屬于Object,又屬于各自的類型。
發(fā)現(xiàn)[],構(gòu)造函數(shù)創(chuàng)建的Date,Object,String,Number,Boolean。既屬于自身,又屬于Object。
舉個(gè)例子,[], Array, Object的關(guān)系:
從 instanceof 能夠判斷出 [ ].__proto__ 指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最終 Object.prototype.__proto__ 指向了null,標(biāo)志著原型鏈的結(jié)束。因此,[]、Array、Object 就在內(nèi)部形成了一條原型鏈:
從原型鏈可以看出,[] 的 proto 直接指向Array.prototype,間接指向 Object.prototype,所以按照 instanceof 的判斷規(guī)則,[] 就是Object的實(shí)例。依次類推,類似的 new Date()、new Person() 也會(huì)形成一條對(duì)應(yīng)的原型鏈 。因此,instanceof 只能判斷兩個(gè)對(duì)象是否屬于實(shí)例關(guān)系, 而不能判斷一個(gè)對(duì)象實(shí)例具體屬于哪種類型。
存在的問(wèn)題:
它假定只有一個(gè)全局執(zhí)行環(huán)境。如果網(wǎng)頁(yè)中包含多個(gè)框架,那實(shí)際上就存在兩個(gè)以上不同的全局執(zhí)行環(huán)境,從而存在兩個(gè)以上不同版本的構(gòu)造函數(shù)。如果你從一個(gè)框架向另一個(gè)框架傳入一個(gè)數(shù)組,那么傳入的數(shù)組與在第二個(gè)框架中原生創(chuàng)建的數(shù)組分別具有各自不同的構(gòu)造函數(shù)。
var iframe = document.createElement("iframe"); document.body.appendChild(iframe); xArray = window.frames[0].Array; var arr = new xArray(1,2,3); // [1,2,3] arr instanceof Array; // false
針對(duì)數(shù)組問(wèn)題,ES5 提供了 Array.isArray() 方法 。該方法用以確認(rèn)某個(gè)對(duì)象本身是否為 Array 類型。
if (Array.isArray(value)){ //對(duì)數(shù)組執(zhí)行某些操作 }
Array.isArray() 本質(zhì)上檢測(cè)的是對(duì)象的 [[Class]] 值,[[Class]] 是對(duì)象的一個(gè)內(nèi)部屬性,里面包含了對(duì)象的類型信息,其格式為 [object Xxx] ,Xxx 就是對(duì)應(yīng)的具體類型 。對(duì)于數(shù)組而言,[[Class]] 的值就是 [object Array] 。
四、constructor定義一個(gè)構(gòu)造函數(shù)Func(),JS引擎會(huì)給Func添加prototype原型,然后再給prototype上添加一個(gè)constructor屬性,并且指向Func的引用。
實(shí)例化一個(gè)函數(shù)func,var func = new Func()。此時(shí)Func原型上的constructor傳遞到func上,因此func.constructor === Func。
Func利用原型對(duì)象上的constructor引用自身,當(dāng)Func作為構(gòu)造函數(shù)來(lái)創(chuàng)建實(shí)例化對(duì)象時(shí),原型上的constructor就會(huì)遺傳到新創(chuàng)建的對(duì)象上。從原型鏈角度講,構(gòu)造函數(shù)Func就是新對(duì)象的func的類型。這樣存在的意義就是新對(duì)象產(chǎn)生之后,可以追蹤數(shù)據(jù)類型。
JavaScript 中的內(nèi)置對(duì)象在內(nèi)部構(gòu)建時(shí)也是這樣做的:
"saucxs".constructor === String //true new String("saucxs").constructor === String //true [].constructor === Array //true new Array([12,56]).constructor === Array //true new Number(12).constructor === Number //true new Function(console.log("saucxs")).constructor === Function //true new Date().constructor === Date //true new Error().constructor === Error //true window.constructor === Window //true document.constructor === HTMLDocument //true
注意:
(1) null 和 undefined 是無(wú)效的對(duì)象,因此是不會(huì)有 constructor 存在的,這兩種類型的數(shù)據(jù)需要通過(guò)其他方式來(lái)判斷。
(2)函數(shù)的 constructor 是不穩(wěn)定的,這個(gè)主要體現(xiàn)在自定義對(duì)象上,當(dāng)開(kāi)發(fā)者重寫(xiě) prototype 后,原有的 constructor 引用會(huì)丟失,constructor 會(huì)默認(rèn)為 Object
為什么變成了 Object?
因?yàn)?prototype 被重新賦值的是一個(gè) { }, { } 是 new Object() 的字面量,因此 new Object() 會(huì)將 Object 原型上的 constructor 傳遞給 { },也就是 Object 本身。
因此,為了規(guī)范開(kāi)發(fā),在重寫(xiě)對(duì)象原型時(shí)一般都需要重新給 constructor 賦值,以保證對(duì)象實(shí)例的類型不被篡改。
五、Object.prototype.toStringtoString() 是 Object 的原型方法,調(diào)用該方法,默認(rèn)返回當(dāng)前對(duì)象的 [[Class]] 。這是一個(gè)內(nèi)部屬性,其格式為字符串 [object xxx] ,其中 xxx 就是對(duì)象的類型。
這個(gè)方法到底是個(gè)啥?可以 先看ES5 規(guī)范地址:https://es5.github.io/#x15.2.4.2
toString方法被調(diào)用的時(shí)候,會(huì)按照這個(gè)步驟執(zhí)行:
(1)如果this的值是undefined,就返回[object Undefined];
(2)如果this的值是null,就返回[object Null];
(3)讓O成為T(mén)oObject(this)的結(jié)果;
(4)讓class成為O的內(nèi)部屬性[[class]]的值;
(5)最后返回由"[object" 和 class 和 "]"三個(gè)部分組成的字符串。
一句話就是:調(diào)用Object.prototype.toString 會(huì)返回一個(gè)"[object" 和 class 和 "]"組成的字符串,而class要判斷對(duì)象的內(nèi)部屬性。
console.log(Object.prototype.toString.call(undefined)) // "[object Undefined]" console.log(Object.prototype.toString.call(null)) // "[object Null]" console.log(Object.prototype.toString.call(Window)) // "[object Function]" var date = new Date(); console.log(Object.prototype.toString.call(date)) // "[object Date]" console.log(Object.prototype.toString.call(Symbol)) // "[object Function]"
注意:通過(guò)call改變this的指向。
所以這個(gè)class的值是識(shí)別對(duì)象類型的關(guān)鍵,所以使用Object.prototype.toString方法識(shí)別出更多的類型,可以識(shí)別出至少11種類型
var number = 1; // [object Number] var string = "123"; // [object String] var boolean = true; // [object Boolean] var und = undefined; // [object Undefined] var nul = null; // [object Null] var obj = {a: 1} // [object Object] var array = [1, 2, 3]; // [object Array] var date = new Date(); // [object Date] var error = new Error(); // [object Error] var reg = /a/g; // [object RegExp] var func = function a(){}; // [object Function] Math //[object Math] JSON //[object JSON]
注意:
1、其實(shí)Math對(duì)象和JSON對(duì)象,并不會(huì)去判斷;
2、Math對(duì)象并不像Date和String那樣對(duì)象的類,沒(méi)有構(gòu)造函數(shù)Math(), Math.sin()這樣的只是函數(shù),不是某一個(gè)對(duì)象的方法。
六、研究jquery的type API使用Object.prototype.toString這個(gè)方法,判斷各種類型就比較輕松了,參考了jquery的源碼的type部分:
function type(obj) { // 一箭雙雕 if (obj == null) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[Object.prototype.toString.call(obj)] || "object" : typeof obj; }
其中class2type部分
var class2type = {}; // 生成class2type映射 "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) { class2type["[object " + item + "]"] = item.toLowerCase(); })
使用:
type(1); //"number" type("123456"); //"string" type(true); //boolean type(undefined); //undefined type(null); //"null" type({name: "saucxs"}); //"object" type([1,2,"saucxs",3,4]); //"array" type(new Date()); // "date" type(new Error()); //"error" type(/^d/); //"regexp" type(function(){console.log("saucxs")}); //"function" type(Symbol); //"function"
這就非常完美的實(shí)現(xiàn)了,對(duì)我們?nèi)粘P枰愋偷呐袛唷?/p>
實(shí)現(xiàn)了判斷日期,正則,錯(cuò)誤類型等。
如果還需要判斷比較復(fù)雜的,比如:空對(duì)象,window對(duì)象,類數(shù)組對(duì)象等等。
七、空對(duì)象EmptyObjectjQuery提供了 isEmptyObject 方法來(lái)判斷是否是空對(duì)象
function isEmptyObject( obj ) { var name; for ( name in obj ) { return false; } return true; }
思路:判斷空對(duì)象就是判斷是是否有屬性值,for循環(huán)一旦執(zhí)行,就說(shuō)明有屬性,有屬性返回false。
console.log(isEmptyObject({})); // true console.log(isEmptyObject([])); // true console.log(isEmptyObject(null)); // true console.log(isEmptyObject(undefined)); // true console.log(isEmptyObject(123)); // true console.log(isEmptyObject("")); // true console.log(isEmptyObject(true)); // true
這個(gè)判斷主要用來(lái)區(qū)別 {} 和 {name: "saucxs"} 就行。
注意點(diǎn):(1)for in 是ES6的屬性,這個(gè)會(huì)遍歷原型上的屬性。(2)使用Object.keys(obj)是ES5的屬性,不會(huì)遍歷原型上的屬性
八、window對(duì)象window對(duì)象是客戶端js的全局對(duì)象,他有一個(gè)window屬性指向自身。根據(jù)這個(gè)特性判斷是否為window對(duì)象。
function isWindow(obj){ return obj != null && obj ===obj.window; }
注意:一個(gè)普通對(duì)象擁有 window 屬性,并且指向自身。比如這個(gè):
function isWindow( obj ) { return obj != null && obj === obj.window; } let fakeWindow = {} fakeWindow.window = fakeWindow isWindow(fakeWindow) // true
是不是可以這么修改呢?
function isWindow(obj) { return !!(window && obj === window) }九、類數(shù)組對(duì)象
如果對(duì)類數(shù)組沒(méi)有概念,舉個(gè)例子:
1、數(shù)組和類數(shù)組
var arr = [,,3];
對(duì)應(yīng)的類數(shù)組是
var arrLike = { 2: 3, length: 3 }
看jquery的源碼
function isArrayLike(obj) { // obj 必須有 length屬性 var length = !!obj && "length" in obj && obj.length; var typeRes = type(obj); // 排除掉函數(shù)和 Window 對(duì)象 if (typeRes === "function" || isWindow(obj)) { return false; } return typeRes === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj; }
所以如果 isArrayLike 返回true,至少要滿足三個(gè)條件之一:
(1)是數(shù)組
(2)長(zhǎng)度為 0
(3)lengths 屬性是大于 0 的數(shù)字類型,并且obj[length - 1]必須存在
第三個(gè)條件:數(shù)組中用逗號(hào)直接跳過(guò)的時(shí)候,我們認(rèn)為該元素是不存在的,類數(shù)組對(duì)象中也就不用寫(xiě)這個(gè)元素,但是最后一個(gè)元素是一定要寫(xiě)的,要不然 length 的長(zhǎng)度就不會(huì)是最后一個(gè)元素的 key 值加 1。比如數(shù)組可以這樣寫(xiě)
var arr = [1,,]; console.log(arr.length) // 2
改寫(xiě)成類數(shù)組
var arrLike = { 0: 1, length: 1 }
所以符合條件的類數(shù)組對(duì)象是一定存在最后一個(gè)元素的!
十、判斷是不是dom元素isElement 判斷是不是 DOM 元素。
isElement = function(obj) { return !!(obj && obj.nodeType === 1); };十一、總結(jié)
判斷類型主要時(shí)四個(gè)方法:(1)typeof;(2)instanceof;(3)constructor;(4)Object.prototype.toString()。
從基本的六種類型判斷,可以使用typeof,如果涉及到對(duì)象的內(nèi)部類型時(shí)候;還可以使用instanceof,檢測(cè)對(duì)象原型的;還可以使用constructor屬性是不是指向他們構(gòu)造函數(shù);需要使用Object.prototype.toString(),如果需要判斷空對(duì)象,可以使用ES6 的 for in 來(lái)判斷,用window屬性指向自身來(lái)判斷是不是window對(duì)象。以及類數(shù)組對(duì)象的判斷,以及判斷是不是dom元素的判斷。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/106933.html
摘要:用對(duì)象字面量創(chuàng)建的對(duì)象會(huì)報(bào)錯(cuò),使用構(gòu)造函數(shù)創(chuàng)建的對(duì)象屬于。發(fā)現(xiàn),構(gòu)造函數(shù)創(chuàng)建的,,,,。從原型鏈角度講,構(gòu)造函數(shù)就是新對(duì)象的的類型。 一、前言 類型判斷有時(shí)候真的頭疼,但是一旦熟練使用就會(huì)覺(jué)得不過(guò)如此。初級(jí)的,會(huì)判斷數(shù)字和字符串。中級(jí)的,會(huì)判斷數(shù)組和對(duì)象。進(jìn)階的,會(huì)判斷日期,正則,錯(cuò)誤類型。高級(jí)的,會(huì)判斷plainObject,空對(duì)象,window對(duì)象等等。 基本類型:String、N...
摘要:專題系列第四篇,講解類型判斷的各種方法,并且跟著寫(xiě)一個(gè)函數(shù)。返回值為表示操作數(shù)類型的一個(gè)字符串??紤]到實(shí)際情況下并不會(huì)檢測(cè)和,所以去掉這兩個(gè)類型的檢測(cè)。 JavaScript專題系列第四篇,講解類型判斷的各種方法,并且跟著 jQuery 寫(xiě)一個(gè) type 函數(shù)。 前言 類型判斷在 web 開(kāi)發(fā)中有非常廣泛的應(yīng)用,簡(jiǎn)單的有判斷數(shù)字還是字符串,進(jìn)階一點(diǎn)的有判斷數(shù)組還是對(duì)象,再進(jìn)階一點(diǎn)的有判...
摘要:專題系列共計(jì)篇,主要研究日常開(kāi)發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖節(jié)流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點(diǎn)是研究專題之函數(shù)組合專題系列第十六篇,講解函數(shù)組合,并且使用柯里化和函數(shù)組合實(shí)現(xiàn)模式需求我們需要寫(xiě)一個(gè)函數(shù),輸入,返回。 JavaScript 專題之從零實(shí)現(xiàn) jQuery 的 extend JavaScritp 專題系列第七篇,講解如何從零實(shí)現(xiàn)一個(gè) jQuery 的 ext...
摘要:專題系列預(yù)計(jì)寫(xiě)二十篇左右,主要研究日常開(kāi)發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖節(jié)流去重類型判斷拷貝最值扁平柯里遞歸亂序排序等,特點(diǎn)是研究和的實(shí)現(xiàn)方式。 JavaScript專題系列第五篇,講解更加復(fù)雜的類型判斷,比如 plainObject、空對(duì)象、類數(shù)組對(duì)象、Window對(duì)象、DOM 元素等 前言 在上篇《JavaScript專題之類型判斷(上)》中,我們抄襲 jQuery 寫(xiě)了一個(gè) typ...
摘要:雖然構(gòu)造函數(shù)或者對(duì)象字面量的方法都可以用來(lái)創(chuàng)建對(duì)象,但是這些方法使用同一個(gè)接口創(chuàng)建很多對(duì)象,會(huì)產(chǎn)生大量的重復(fù)代碼。參考資料冴羽的專題系列中高級(jí)前端面試手寫(xiě)代碼無(wú)敵秘籍前端筆試之手寫(xiě)代碼一本系列會(huì)從面試的角度出發(fā)圍繞JavaScript,Node.js(npm包)以及框架三個(gè)方面來(lái)對(duì)常見(jiàn)的模擬實(shí)現(xiàn)進(jìn)行總結(jié),具體源代碼放在github項(xiàng)目上,長(zhǎng)期更新和維護(hù) showImg(https://use...
閱讀 3667·2023-04-25 23:32
閱讀 2065·2019-08-30 15:55
閱讀 2680·2019-08-30 15:52
閱讀 3134·2019-08-30 10:54
閱讀 867·2019-08-29 16:16
閱讀 678·2019-08-29 15:09
閱讀 3681·2019-08-26 14:05
閱讀 1656·2019-08-26 13:22