編寫javascript代碼的時候常常要判斷變量,字面量的類型,可以用typeof,instanceof,Array.isArray(),等方法,究竟哪一種最方便,最實用,最省心呢?本問探討這個問題。

          1.?typeof

          1.1?語法

          typeof返回一個字符串,表示未經(jīng)計算的操作數(shù)的類型。

          語法:typeof(operand) | typeof operand
          參數(shù):一個表示對象或原始值的表達式,其類型將被返回
          描述:typeof可能返回的值如下:

          類型 結(jié)果
          Undefined “undefined”
          Null “object”
          Boolean “boolean”
          Number “number”
          Bigint “bigint”
          String “string”
          Symbol “symbol”
          宿主對象(由JS環(huán)境提供) 取決于具體實現(xiàn)
          Function對象 “function”
          其他任何對象 “object”

          從定義和描述上來看,這個語法可以判斷出很多的數(shù)據(jù)類型,但是仔細觀察,typeof?null居然返回的是“object”,讓人摸不著頭腦,下面會具體介紹,先看看這個效果:
          // 數(shù)值 console.log(typeof 37) // number console.log(typeof 3.14) // number
          console.log(typeof(42)) // number console.log(typeof Math.LN2) // number
          console.log(typeof Infinity) // number console.log(typeof NaN) // number
          盡管它是Not-A-Number的縮寫,實際NaN是數(shù)字計算得到的結(jié)果,或者將其他類型變量轉(zhuǎn)化成數(shù)字失敗的結(jié)果 console.log(Number(1))
          //number Number(1)構(gòu)造函數(shù)會把參數(shù)解析成字面量 console.log(typeof 42n) //bigint // 字符串
          console.log(typeof '') //string console.log(typeof 'boo') // string console.log(
          typeof `template literal`) // string console.log(typeof '1') //string
          內(nèi)容為數(shù)字的字符串仍然是字符串 console.log(typeof(typeof 1)) //string,typeof總是返回一個字符串
          console.log(typeof String(1)) //string String將任意值轉(zhuǎn)換成字符串 // 布爾值 console.log(
          typeof true) // boolean console.log(typeof false) // boolean console.log(typeof
          Boolean(1))// boolean Boolean會基于參數(shù)是真值還是虛值進行轉(zhuǎn)換 console.log(typeof !!(1)) //
          boolean 兩次調(diào)用!!操作想短語Boolean() // Undefined console.log(typeof undefined) //
          undefined console.log(typeof declaredButUndefinedVariabl) // 未賦值的變量返回undefined
          console.log(typeof undeclaredVariable ) // 未定義的變量返回undefined // 對象 console.log(
          typeof {a: 1}) //object console.log(typeof new Date()) //object console.log(
          typeof /s/) // 正則表達式返回object // 下面的例子令人迷惑,非常危險,沒有用處,應(yīng)避免使用,new操作符返回的實例都是對象
          console.log(typeof new Boolean(true)) // object console.log(typeof new
          Number(1))// object console.log(typeof new String('abc')) // object // 函數(shù)
          console.log(typeof function () {}) // function console.log(typeof class C { })
          // function console.log(typeof Math.sin) // function?
          1.2?迷之null

          javascript誕生以來,typeof null都是返回‘object’的,這個是因為javascript中的值由兩部分組成,一部分是表示類型的標簽
          ,另一部分是表示實際的值。對象類型的值類型標簽是0,不巧的是null表示空指針,它的類型標簽也被設(shè)計成0,于是就有這個typeof?null ===
          ‘object’這個‘惡魔之子’。

          曾經(jīng)有ECMAScript提案讓typeof?null返回‘null’,但是該提案被拒絕了。

          1.3?使用new操作符

          除Function之外所有構(gòu)造函數(shù)的類型都是‘object’,如下:
          var str = new String('String'); var num = new Number(100) console.log(typeof
          str)// object console.log(typeof num) // object var func = new Function()
          console.log(typeof func) // function?
          1.4?語法中的括號

          typeof運算的優(yōu)先級要高于“+”操作,但是低于圓括號
          var iData = 99 console.log(typeof iData + ' Wisen') // number Wisen
          console.log(typeof (iData + 'Wisen')) // string?
          1.5?判斷正則表達式的兼容性問題
          typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1 typeof /s/ ===
          'object';// Firefox 5+ , 符合 ECMAScript 5.1?
          1.6?錯誤

          ECMAScript
          2015之前,typeof總能保證對任何所給的操作數(shù)都返回一個字符串,即使是沒有聲明,沒有賦值的標示符,typeof也能返回undefined,也就是說使用typeof永遠不會報錯。


          但是ES6中加入了塊級作用域以及l(fā)et,const命令之后,在變量聲明之前使用由let,const聲明的變量都會拋出一個ReferenceError錯誤,塊級作用域變量在塊的頭部到聲明變量之間是“暫時性死區(qū)”,在這期間訪問變量會拋出錯誤。如下:
          console.log(typeof undeclaredVariable) // 'undefined' console.log(typeof
          newLetVariable)// ReferenceError console.log(typeof newConstVariable) //
          ReferenceError console.log(typeof newClass) // ReferenceError let
          newLetVariable const newConstVariable= 'hello' class newClass{}?
          1.7?例外

          當(dāng)前所有瀏覽器都暴露一個類型為undefined的非標準宿主對象document.all。typeof?document.all ===
          'undefined'。景觀規(guī)范允許為非標準的外來對象自定義類型標簽,單要求這些類型標簽與已有的不同,document.all的類型標簽為undefined的例子在web領(lǐng)域被歸類為對原ECMA?javascript標準的“故意侵犯”,可能就是瀏覽器的惡作劇。

          總結(jié):typeof返回變量或者值的類型標簽,雖然對大部分類型都能返回正確結(jié)果,但是對null,構(gòu)造函數(shù)實例,正則表達式這三種不太理想。?

          2.?instanceof

          2.1?語法

          instanceof運算符用于檢測實例對象(參數(shù))的原型鏈上是否出現(xiàn)構(gòu)造函數(shù)的prototype。

          語法:object?instanceof?constructor
          參數(shù):object?某個實例對象
          ? ? ? ? ? constructor?某個構(gòu)造函數(shù)
          描述:instanceof運算符用來檢測constructor.property是否存在于參數(shù)object的原型鏈上。
          // 定義構(gòu)造函數(shù) function C() { } function D() { } var o = new C() console.log(o
          instanceof C) //true,因為Object.getPrototypeOf(0) === C.prototype console.log(o
          instanceof D) //false,D.prototype不在o的原型鏈上 console.log(o instanceof Object) //
          true 同上 C.prototype = {} var o2 = new C() console.log(o2 instanceof C) // true
          console.log(oinstanceof C) // false C.prototype指向了一個空對象,這個空對象不在o的原型鏈上
          D.prototype =new C() // 繼承 var o3 = new D() console.log(o3 instanceof D) // true
          console.log(o3instanceof C) // true C.prototype現(xiàn)在在o3的原型鏈上

          需要注意的是,如果表達式obj?instanceof?Foo返回true,則并不意味著該表達式會永遠返回true,應(yīng)為Foo.prototype屬性的值可能被修改,修改之后的值可能不在obj的原型鏈上,這時表達式的值就是false了。另外一種情況,改變obj的原型鏈的情況,雖然在當(dāng)前ES規(guī)范中,只能讀取對象的原型而不能修改它,但是借助非標準的__proto__偽屬性,是可以修改的,比如執(zhí)行obj.__proto__
          = {}后,obj instanceof
          Foo就返回false了。此外ES6中Object.setPrototypeOf(),Reflect.setPrototypeOf()都可以修改對象的原型。

          instanceof和多全局對象(多個iframe或多個window之間的交互)


          瀏覽器中,javascript腳本可能需要在多個窗口之間交互。多個窗口意味著多個全局環(huán)境,不同全局環(huán)境擁有不同的全局對象,從而擁有不同的內(nèi)置構(gòu)造函數(shù)。這可能會引發(fā)一些問題。例如表達式[]
          instanceof window.frames[0].Array會返回false,因為Array.prototype !==
          window.frames[0].Array.prototype。


          起初,這樣可能沒有意義,但是當(dāng)在腳本中處理多個frame或多個window以及通過函數(shù)將對象從一個窗口傳遞到另一個窗口時,這就是一個非常有意義的話題。實際上,可以通過Array.isArray(myObj)或者Object.prototype.toString.call(myObj)
          = "[object Array]"來安全的檢測傳過來的對象是否是一個數(shù)組。

          2.2?示例

          String對象和Date對象都屬于Object類型(它們都由Object派生出來)。

          但是,使用對象文字符號創(chuàng)建的對象在這里是一個例外,雖然原型未定義,但是instanceof?of?Object返回true。
          var simpleStr = "This is a simple string"; var myString = new String(); var
          newStr =new String("String created with constructor"); var myDate = new Date();
          var myObj = {}; var myNonObj = Object.create(null); console.log(simpleStr
          instanceof String); // 返回 false,雖然String.prototype在simpleStr的原型鏈上,但是后者是字面量,不是對象
          console.log(myStringinstanceof String); // 返回 true console.log(newStr instanceof
          String);// 返回 true console.log(myString instanceof Object); // 返回 true
          console.log(myObjinstanceof Object); // 返回 true, 盡管原型沒有定義 console.log(({})
          instanceof Object); // 返回 true, 同上 console.log(myNonObj instanceof Object); //
          返回 false, 一種創(chuàng)建非 Object 實例的對象的方法 console.log(myString instanceof Date); //返回
          false console.log( myDate instanceof Date); // 返回 true console.log(myDate
          instanceof Object); // 返回 true console.log(myDate instanceof String); // 返回
          false?
          注意:instanceof運算符的左邊必須是一個對象,像"string"
          instanceof?String,true?instanceof?Boolean這樣的字面量都會返回false。

          下面代碼創(chuàng)建了一個類型Car,以及該類型的對象實例mycar,instanceof運算符表明了這個myca對象既屬于Car類型,又屬于Object類型。
          function Car(make, model, year) { this.make = make; this.model = model; this
          .year = year; } var mycar = new Car("Honda", "Accord", 1998); var a = mycar
          instanceof Car; // 返回 true var b = mycar instanceof Object; // 返回 true?
          不是...的實例

          要檢測對象不是某個構(gòu)造函數(shù)的實例時,可以使用!運算符,例如if(!(mycar instanceof Car))

          instanceof雖然能夠判斷出對象的類型,但是必須要求這個參數(shù)是一個對象,簡單類型的變量,字面量就不行了,很顯然,這在實際編碼中也是不夠?qū)嵱谩?br>
          總結(jié):obj?instanceof?constructor雖然能判斷出對象的原型鏈上是否有構(gòu)造函數(shù)的原型,但是只能判斷出對象類型變量,字面量是判斷不出的。

          3. Object.prototype.toString()

          3.1.?語法

          toString()方法返回一個表示該對象的字符串。

          語法:obj.toString()
          返回值:一個表示該對象的字符串

          描述:每個對象都有一個toString()方法,該對象被表示為一個文本字符串時,或一個對象以預(yù)期的字符串方式引用時自動調(diào)用。默認情況下,toString()方法被每個Object對象繼承,如果此方法在自定義對象中未被覆蓋,toString()返回“[object
          type]”,其中type是對象的類型,看下面代碼:
          var o = new Object(); console.log(o.toString()); // returns [object Object]?
          注意:如ECMAScript 5和隨后的Errata中所定義,從javascript1.8.5開始,toString()調(diào)用null返回[object,
          Null],undefined返回[object Undefined]

          3.2. 示例

          覆蓋默認的toString()方法


          可以自定義一個方法,來覆蓋默認的toString()方法,該toString()方法不能傳入?yún)?shù),并且必須返回一個字符串,自定義的toString()方法可以是任何我們需要的值,但如果帶有相關(guān)的信息,將變得非常有用。

          下面代碼中定義Dog對象類型,并在構(gòu)造函數(shù)原型上覆蓋toString()方法,返回一個有實際意義的字符串,描述當(dāng)前dog的姓名,顏色,性別,飼養(yǎng)員等信息。
          function Dog(name,breed,color,sex) { this.name = name; this.breed = breed; this
          .color = color; this.sex = sex; } Dog.prototype.toString = function
          dogToString() {return "Dog " + this.name + " is a " + this.sex + " " + this
          .color + " " +this.breed } var theDog = new Dog("Gabby", "Lab", "chocolate",
          "female"); console.log(theDog.toString()) //Dog Gabby is a female chocolate Lab?
          4.?使用toString()檢測數(shù)據(jù)類型


          目前來看toString()方法能夠基本滿足javascript數(shù)據(jù)類型的檢測需求,可以通過toString()來檢測每個對象的類型。為了每個對象都能通過Object.prototype.toString()來檢測,需要以Function.prototype.call()或者Function.prototype.apply()的形式來檢測,傳入要檢測的對象或變量作為第一個參數(shù),返回一個字符串"[object
          type]"。
          // null undefined console.log(Object.prototype.toString.call(null)) //[object
          Null] 很給力 console.log(Object.prototype.toString.call(undefined)) //[object
          Undefined] 很給力 // Number console.log(Object.prototype.toString.call(Infinity))
          //[object Number]
          console.log(Object.prototype.toString.call(Number.MAX_SAFE_INTEGER))//[object
          Number] console.log(Object.prototype.toString.call(NaN)) //[object
          Number],NaN一般是數(shù)字運算得到的結(jié)果,返回Number還算可以接受
          console.log(Object.prototype.toString.call(1))//[object Number] var n = 100
          console.log(Object.prototype.toString.call(n))//[object Number]
          console.log(Object.prototype.toString.call(0))// [object Number]
          console.log(Object.prototype.toString.call(Number(1)))//[object Number] 很給力
          console.log(Object.prototype.toString.call(new Number(1))) //[object Number] 很給力
          console.log(Object.prototype.toString.call('1'))//[object String]
          console.log(Object.prototype.toString.call(new String('2'))) // [object String]
          // Boolean console.log(Object.prototype.toString.call(true)) // [object Boolean]
          console.log(Object.prototype.toString.call(new Boolean(1))) //[object Boolean]
          // Array console.log(Object.prototype.toString.call(new Array(1))) // [object
          Array] console.log(Object.prototype.toString.call([])) // [object Array] //
          Object console.log(Object.prototype.toString.call(new Object())) // [object
          Object] function foo() {} let a = new foo()
          console.log(Object.prototype.toString.call(a))// [object Object] // Function
          console.log(Object.prototype.toString.call(Math.floor))//[object Function]
          console.log(Object.prototype.toString.call(foo))//[object Function] // Symbol
          console.log(Object.prototype.toString.call(Symbol('222')))//[object Symbol] //
          RegExp console.log(Object.prototype.toString.call(/sss/)) //[object RegExp]?

          上面的結(jié)果,除了NaN返回Number稍微有點差池之外其他的都返回了意料之中的結(jié)果,都能滿足實際開發(fā)的需求,于是我們可以寫一個通用的函數(shù)來檢測變量,字面量的類型。如下:
          let Type = (function () { let type = {}; let typeArr = ['String', 'Object',
          'Number', 'Array', 'Undefined', 'Function', 'Null', 'Symbol', 'Boolean',
          'RegExp', 'BigInt']; for (let i = 0; i < typeArr.length; i++) { (function
          (name) { type['is' + name] = function (obj) { return
          Object.prototype.toString.call(obj) === '[object ' + name + ']' }
          })(typeArr[i]) }return type })() let s = true console.log(Type.isBoolean(s)) //
          true console.log(Type.isRegExp(/22/)) // true?
          除了能檢測ECMAScript規(guī)定的八種數(shù)據(jù)類型(七種原始類型,Boolean,Null,Undefined,Number,BigInt,String,
          Symbol,一種復(fù)合類型Object)之外,還能檢測出正則表達式RegExp,F(xiàn)unction這兩種類型,基本上能滿足開發(fā)中的判斷數(shù)據(jù)類型需求。

          5.?判斷相等


          既然說道這里,不妨說一說另一個開發(fā)中常見的問題,判斷一個變量是否等于一個值。ES5中比較兩個值是否相等,可以使用相等運算符(==),嚴格相等運算符(===),但它們都有缺點,==?會將‘4’轉(zhuǎn)換成4,后者NaN不等于自身,以及+0
          !===
          -0。ES6中提出”Same-value?equality“(同值相等)算法,用來解決這個問題。Object.is就是部署這個算法的新方法,它用來比較兩個值是否嚴格相等,與嚴格比較運算(===)行為基本一致。
          console.log(5 == '5') // true console.log(NaN == NaN) // false console.log(+0
          == -0)// true console.log({} == {}) // false console.log(5 === '5') // false
          console.log(NaN === NaN)// false console.log(+0 === -0) // true console.log({}
          === {})// false
          Object.js()不同之處有兩處,一是+0不等于-0,而是NaN等于自身,如下:
          let a = {} let b = {} let c = b console.log(a === b) // false console.log(b
          === c)// true console.log(Object.is(b, c)) // true?
          注意兩個空對象不能判斷相等,除非是將一個對象賦值給另外一個變量,對象類型的變量是一個指針,比較的也是這個指針,而不是對象內(nèi)部屬性,對象原型等。

          ?

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                青青草97国产精品麻豆 | 久久伦理影院 | 少妇高潮一区二区三区99刮毛 | 亚洲人在线观看 | 无码毛片在线看 |