免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      JavaScript中的數(shù)據(jù)類型判斷

      typeof

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

      語法

      typeof 運(yùn)算符后接操作數(shù):

      typeof operand

      typeof(operand)

      參數(shù)

      operand 一個(gè)表示對(duì)象或原始值的表達(dá)式,其類型將被返回。

      描述

      下面總結(jié)了 typeof 可能的返回值。有關(guān)類型和原始值的更多信息,可查看 JavaScript 數(shù)據(jù)結(jié)構(gòu) 頁面。

      類型

      結(jié)果

      Undefined

      “undefined”

      Null

      “object” (見下文)

      Boolean

      “boolean”

      Number

      “number”

      BigInt (ECMAScript 2020 新增)

      “bigint”

      String

      “string”

      Symbol (ECMAScript 2015 新增)

      “symbol”

      宿主對(duì)象(由 JS 環(huán)境提供)

      取決于具體實(shí)現(xiàn)

      Function 對(duì)象 (按照 ECMA-262 規(guī)范實(shí)現(xiàn) [[Call]])

      “function”

      其他任何對(duì)象

      “object”

      原始值

      除對(duì)象類型(object)以外的其它任何類型定義的不可變的值(值本身無法被改變)。例如(與 C 語言不同),JavaScript 中字符串是不可變的(譯注:如,JavaScript 中對(duì)字符串的操作一定返回了一個(gè)新字符串,原始字符串并沒有被改變)。我們稱這些類型的值為“原始值”。

      特性

      1、typeof 總是返回一個(gè)字符串。

      2、typeof 能正確判斷原始值的類型,null 除外;引用類型數(shù)據(jù)能正確判斷 Function、函數(shù)的類型,其他的都會(huì)返回 ‘object’。

      示例

      // 數(shù)值console.log(typeof 37 === ‘number’) // trueconsole.log(typeof 3.14 === ‘number’) // trueconsole.log(typeof (42) === ‘number’) // trueconsole.log(typeof Math.LN2 === ‘number’) // trueconsole.log(typeof Infinity === ‘number’) // trueconsole.log(typeof NaN === ‘number’) // true 盡管它是 “Not-A-Number” (非數(shù)值) 的縮寫console.log(typeof Number(1) === ‘number’) // true Number 會(huì)嘗試把參數(shù)解析成數(shù)值console.log(typeof 42n === ‘bigint’) // true// 字符串console.log(typeof ” === ‘string’) // trueconsole.log(typeof ‘bla’ === ‘string’) // trueconsole.log(typeof `template literal` === ‘string’) // trueconsole.log(typeof ‘1’ === ‘string’) // true 注意內(nèi)容為數(shù)字的字符串仍是字符串console.log(typeof (typeof 1) === ‘string’) // true typeof 總是返回一個(gè)字符串console.log(typeof String(1) === ‘string’) // true String 將任意值轉(zhuǎn)換為字符串,比 toString 更安全// 布爾值console.log(typeof true === ‘boolean’) // trueconsole.log(typeof false === ‘boolean’) // trueconsole.log(typeof Boolean(1) === ‘boolean’) // Boolean() 會(huì)基于參數(shù)是真值還是虛值進(jìn)行轉(zhuǎn)換console.log(typeof !!(1) === ‘boolean’) // true 兩次調(diào)用 ! (邏輯非) 操作符相當(dāng)于 Boolean()// Symbolsconsole.log(typeof Symbol() === ‘symbol’) // trueconsole.log(typeof Symbol(‘foo’) === ‘symbol’) // trueconsole.log(typeof Symbol.iterator === ‘symbol’) // true// Undefinedconsole.log(typeof undefined === ‘undefined’) // trueconsole.log(typeof declaredButUndefinedVariable === ‘undefined’) // trueconsole.log(typeof undeclaredVariable === ‘undefined’) // true// 對(duì)象console.log(typeof { a: 1 } === ‘object’) // true// 使用 Array.isArray 或者 Object.prototype.toString.call// 區(qū)分數(shù)組和普通對(duì)象console.log(typeof [1, 2, 4] === ‘object’) // trueconsole.log(typeof new Date() === ‘object’) // trueconsole.log(typeof /regex/ === ‘object’) // true 歷史結(jié)果請(qǐng)參閱正則表達(dá)式部分// 使用 new 操作符// 除 Function 外的所有構(gòu)造函數(shù)的類型都是 ‘object’var func = new Function()console.log(typeof func) // 返回 ‘function’var A = function() {}var b = new A()console.log(typeof b) // 返回 ‘object’// 下面的例子令人迷惑,非常危險(xiǎn),沒有用處。避免使用它們。console.log(typeof new Boolean(true) === ‘object’) // trueconsole.log(typeof new Number(1) === ‘object’) // trueconsole.log(typeof new String(‘abc’) === ‘object’) // true// 函數(shù)console.log(typeof function () { } === ‘function’) // trueconsole.log(typeof class C { } === ‘function’) // trueconsole.log(typeof Math.sin === ‘function’) // true// Null// JavaScript 誕生以來便如此console.log(typeof null === ‘object’) // true

      在 JavaScript 最初的實(shí)現(xiàn)中,JavaScript 中的值是由一個(gè)表示類型的標(biāo)簽和實(shí)際數(shù)據(jù)值表示的。對(duì)象的類型標(biāo)簽是 0。由于 null 代表的是空指針(大多數(shù)平臺(tái)下值為 0x00),因此,null 的類型標(biāo)簽是 0,typeof null 也因此返回 “object”。(參考來源)

      console.log(typeof 0); // numberconsole.log(typeof BigInt(Number.MAX_SAFE_INTEGER)); // bigintconsole.log(typeof ‘0’); // stringconsole.log(typeof true); // booleanconsole.log(typeof undefined); // undefinedconsole.log(typeof function () { }); // functionconsole.log(typeof Symbol); // functionconsole.log(typeof Symbol()); // symbolconsole.log(typeof Date); // functionconsole.log(typeof Date()); // stringconsole.log(typeof new Date); // objectconsole.log(typeof new Date()); // objectconsole.log(typeof RegExp); // functionconsole.log(typeof RegExp()); // objectconsole.log(typeof new RegExp); // objectconsole.log(typeof new RegExp()); // objectconsole.log(typeof []); // objectconsole.log(typeof {}); // objectconsole.log(typeof null); // object

      如果我們想判斷一個(gè)對(duì)象的正確類型,可以考慮使用 instanceof,因?yàn)閮?nèi)部機(jī)制是通過 判斷實(shí)例對(duì)象的 __proto__ 和生成該實(shí)例的構(gòu)造函數(shù)的 prototype 是不是引用的同一個(gè)地址(也就是原型鏈的方式)來判斷的。

      錯(cuò)誤

      在 ECMAScript 2015 之前,typeof 總能保證對(duì)任何所給的操作數(shù)返回一個(gè)字符串。即便是沒有聲明的標(biāo)識(shí)符,typeof 也能返回 ‘undefined’。使用 typeof 永遠(yuǎn)不會(huì)拋出錯(cuò)誤。

      但在加入了塊級(jí)作用域的 let 和 const 之后,在其被聲明之前對(duì)塊中的 let 和 const 變量使用 typeof 會(huì)拋出一個(gè) ReferenceError。塊作用域變量在塊的頭部處于“暫存死區(qū)”,直至其被初始化,在這期間,訪問變量將會(huì)引發(fā)錯(cuò)誤。

      typeof undeclaredVariable === ‘undefined’;typeof newLetVariable; // ReferenceErrortypeof newConstVariable; // ReferenceErrortypeof newClass; // ReferenceErrorlet newLetVariable;const newConstVariable = ‘hello’;class newClass{};

      instanceof

      instanceof 運(yùn)算符用于檢測(cè)構(gòu)造函數(shù) prototype 屬性是否出現(xiàn)在某個(gè)實(shí)例對(duì)象的原型鏈上??梢杂脕砼袛喽紝儆?Object 類型和一些特殊情況的對(duì)象,如:數(shù)組和對(duì)象,但不能用于基礎(chǔ)數(shù)據(jù)類型。

      語法

      object instanceof constructor

      參數(shù)

      object 某個(gè)實(shí)例對(duì)象

      constructor 某個(gè)構(gòu)造函數(shù)

      描述

      instanceof 運(yùn)算符用來檢測(cè) constructor.prototype 是否存在于參數(shù) object 的原型鏈上。

      示例

      B instanceof A:判斷 B 是否為 A 的實(shí)例,可以用于繼承關(guān)系中

      function Car(make, model, year) { this.make = make; this.model = model; this.year = year;}const auto = new Car(‘Honda’, ‘Accord’, 1998);console.log(auto instanceof Car);// expected output: trueconsole.log(auto instanceof Object);// expected output: true// 定義構(gòu)造函數(shù)function C(){}function D(){}var o = new C();o instanceof C; // true,因?yàn)?Object.getPrototypeOf(o) === C.prototypeo instanceof D; // false,因?yàn)?D.prototype 不在 o 的原型鏈上o instanceof Object; // true,因?yàn)?Object.prototype.isPrototypeOf(o) 返回 trueC.prototype instanceof Object // true,同上C.prototype = {};var o2 = new C();o2 instanceof C; // trueo instanceof C; // false,C.prototype 指向了一個(gè)空對(duì)象,這個(gè)空對(duì)象不在 o 的原型鏈上.D.prototype = new C(); // 繼承var o3 = new D();o3 instanceof D; // trueo3 instanceof C; // true 因?yàn)?C.prototype 現(xiàn)在在 o3 的原型鏈上

      需要注意的是,如果表達(dá)式 obj instanceof Foo 返回 true,則并不意味著該表達(dá)式會(huì)永遠(yuǎn)返回 true,因?yàn)?Foo.prototype 屬性的值有可能會(huì)改變,改變之后的值很有可能不存在于 obj 的原型鏈上,這時(shí)原表達(dá)式的值就會(huì)成為 false。另外一種情況下,原表達(dá)式的值也會(huì)改變,就是改變對(duì)象 obj 的原型鏈的情況,雖然在目前的ES規(guī)范中,我們只能讀取對(duì)象的原型而不能改變它,但借助于非標(biāo)準(zhǔn)的 __proto__ 偽屬性,是可以實(shí)現(xiàn)的。比如執(zhí)行 obj.__proto__ = {} 之后,obj instanceof Foo 就會(huì)返回 false 了。

      A 是 B 的父對(duì)象,c 是 B 的實(shí)例,c instanceof A 與 c instanceof B 結(jié)果均為 true。

      function A() { }function B() { }B.prototype = new A()const c = new B()console.log(c instanceof B); // trueconsole.log(c instanceof A); // trueconsole.log(A instanceof B); // falseconsole.log(B instanceof A); // falseconsole.log(B.__proto__ === A.prototype); // falseconsole.log(B.prototype.__proto__ === A.prototype); // trueconsole.log(c instanceof Object); // true c 屬于console.log(B instanceof Object); // trueconsole.log(A instanceof Object); // true

      演示 String 對(duì)象和 Date 對(duì)象都屬于 Object 類型和一些特殊情況

      下面的代碼使用了 instanceof 來證明:String 和 Date 對(duì)象同時(shí)也屬于Object 類型(他們是由 Object 類派生出來的)。

      但是,使用對(duì)象文字符號(hào)創(chuàng)建的對(duì)象在這里是一個(gè)例外:雖然原型未定義,但 instanceof 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, 非對(duì)象實(shí)例,因此返回 falseconsole.log(myString instanceof String) // 返回 trueconsole.log(newStr instanceof String) // 返回 trueconsole.log(myString instanceof Object) // 返回 trueconsole.log(myObj instanceof Object) // 返回 true, 盡管原型沒有定義console.log(({}) instanceof Object) // 返回 true, 同上console.log(myNonObj instanceof Object) // 返回 false, 一種創(chuàng)建非 Object 實(shí)例的對(duì)象的方法console.log(myString instanceof Date) // 返回 falseconsole.log(myDate instanceof Date) // 返回 trueconsole.log(myDate instanceof Object) // 返回 trueconsole.log(myDate instanceof String) // 返回 false

      Object.prototype.toString.call(object)/Object.prototype.toString.apply(object)

      toString.call() 或 toString.apply() 方法幾乎可以精準(zhǔn)判斷各類數(shù)據(jù)的類型。

      console.log(Object.prototype.toString.call(“kevin”)) // [object String]console.log(Object.prototype.toString.call(18)) // [object Number]console.log(Object.prototype.toString.call(true)) // [object Boolean]console.log(Object.prototype.toString.call(undefined)) // [object Undefined]console.log(Object.prototype.toString.call(null)) // [object Null]console.log(Object.prototype.toString.call(NaN)) // [object Number]console.log(Object.prototype.toString.call({ name: “kevin” })) // [object Object]console.log(Object.prototype.toString.call(function () { })) // [object Function]console.log(Object.prototype.toString.call([])) // [object Array]console.log(Object.prototype.toString.call(new Date)) // [object Date]console.log(Object.prototype.toString.call(/d/)) // [object RegExp]console.log(Object.prototype.toString.call(Math)) // [object Math]function Person() { }console.log(Object.prototype.toString.call(new Person)) // [object Object]var o = { [Symbol.toStringTag]: “A” }console.log(Object.prototype.toString.call(o)) // [object A]console.log(window.toString()) // “[object Window]”console.log(Object.prototype.toString.call(window)) // “[object Window]”console.log(Object.prototype.toString.call(Symbol())); // “[object Symbol]”// 封裝function getTypeof(data) { let dataType = Object.prototype.toString.call(data); return dataType.slice(8, -1)}console.log(getTypeof(18)) // Numberconsole.log(getTypeof(“kevin”)) // Stringconsole.log(getTypeof(new Date)) // Dateconsole.log(getTypeof([])) // Arrayconsole.log(getTypeof({})) // Objectfunction Person() { }console.log(getTypeof(new Person)) // Objectconsole.log(getTypeof(new Person())) // Object

      語法

      obj.toString()

      返回值

      一個(gè)表示該對(duì)象的字符串

      描述

      每個(gè)對(duì)象都有一個(gè) toString() 方法,當(dāng)該對(duì)象被表示為一個(gè)文本值時(shí),或者一個(gè)對(duì)象以預(yù)期的字符串方式引用時(shí)自動(dòng)調(diào)用。默認(rèn)情況下,toString() 方法被每個(gè) Object 對(duì)象繼承。如果此方法在自定義對(duì)象中未被覆蓋,toString() 返回 “[object type]”,其中 type 是對(duì)象的類型。以下代碼說明了這一點(diǎn):

      var o = new Object();console.log(o.toString()); // [object Object]

      備注:如 ECMAScript 5 和隨后的 Errata 中所定義,從 JavaScript 1.8.5 開始,toString() 調(diào)用 null 返回[object Null],undefined 返回 [object Undefined]。請(qǐng)參閱下面的使用toString()檢測(cè)對(duì)象類型。

      示例

      覆蓋默認(rèn)的 toString 方法

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

      以下代碼定義了 Dog 對(duì)象類型,并創(chuàng)建了一個(gè) Dog 類型的 theDog 對(duì)象:

      function Dog(name,breed,color,sex) { this.name = name; this.breed = breed; this.color = color; this.sex = sex;}var theDog = new Dog(“Gabby”, “Lab”, “chocolate”, “female”);// 如果當(dāng)前的對(duì)象調(diào)用了 toString() 方法,它將會(huì)返回從 Object繼承而來的 toString() 方法的返回默認(rèn)值:console.log(theDog.toString()); // 返回 [object Object]// 下面的代碼中定義了一個(gè)叫做 dogToString() 的方法來覆蓋默認(rèn)的 toString() 方法。// 這個(gè)方法生成一個(gè) “property = value;” 形式的字符串,該字符串包含了當(dāng)前對(duì)象的 name、breed、color 和 sex 的值。Dog.prototype.toString = function dogToString() { var ret = “Dog ” + this.name + ” is a ” + this.sex + ” ” + this.color + ” ” + this.breed; return ret;}// 也可以這樣寫Dog.prototype.toString = function dogToString() { return `Dog ${this.name} is a ${this.sex} ${this.color} ${this.breed}`;}// 使用上述代碼,任何時(shí)候在字符串上下文中使用 theDog.toString() 時(shí),// JavaScript 都會(huì)自動(dòng)調(diào)用 dogToString() 方法(dogToString() 可以是一個(gè)匿名函數(shù)),并且返回以下字符串:// “Dog Gabby is a female chocolate Lab”console.log(theDog.toString()); // 返回 “Dog Gabby is a female chocolate Lab”// 也可以這樣寫Dog.prototype.toString = function dogToString() { return ‘[object Dog]’;}Dog.prototype[Symbol.toStringTag] = ‘Dog’// 也可以這樣寫theDog[Symbol.toStringTag] = ‘Dog’console.log(theDog.toString()); // 返回 [object Dog]console.log(Dog.prototype.toString()); // 返回 [object Dog]console.log(Dog.prototype.toString.call(theDog)); // 返回 [object Dog]console.log(Object.prototype.toString.call(theDog)); // 返回 [object Object]

      使用 toString() 檢測(cè)對(duì)象

      可以通過 toString() 來獲取每個(gè)對(duì)象的類型。為了每個(gè)對(duì)象都能通過 Object.prototype.toString() 來檢測(cè),需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式來調(diào)用,傳遞要檢查的對(duì)象作為第一個(gè)參數(shù),稱為 thisArg。

      var toString = Object.prototype.toString;toString.call(new Date); // [object Date]toString.call(new String); // [object String]toString.call(Math); // [object Math]//Since JavaScript 1.8.5toString.call(undefined); // [object Undefined]toString.call(null); // [object Null]

      檢測(cè)原理

      Object.prototype.toString.call(obj) 類型檢測(cè)的原理是什么?首先我們來看一下 toString() 方法:

      var num = 1console.log(num.toString()) // ‘1’var str = ‘kevin’console.log(str.toString()) // ‘kevin’var bool = falseconsole.log(bool.toString()) // ‘false’var arr = [1, 2, 3]console.log(arr.toString()) // ‘1,2,3’var obj = { name: ‘kevin’ }console.log(obj.toString()) // ‘[object Object]’var fn = function(){}console.log(fn.toString()) // ‘function(){}’console.log(JSON.toString()) // ‘[object JSON]’console.log(Atomics.toString()) // ‘[object Atomics]’console.log(null.toString()) // Cannot read property ‘toString’ of nullconsole.log(undefined.toString() // Cannot read property ‘toString’ of undefinedconsole.log(window.toString()) // ‘[object Window]’

      從以上示例可以知道 toString 是將數(shù)據(jù)轉(zhuǎn)換為字符串(null 和 undefined 除外),并且各種類型的數(shù)據(jù)轉(zhuǎn)換為字符串的方式又不一樣。即若參數(shù)不為 null 或 undefined,則將參數(shù)轉(zhuǎn)為對(duì)象,再作判斷。對(duì)于原始類型,轉(zhuǎn)為對(duì)象的方法即裝箱。

      轉(zhuǎn)為對(duì)象后,取得該對(duì)象的 [Symbol.toStringTag] 屬性值(可能會(huì)遍歷原型鏈)作為 tag,如無該屬性,或該屬性值不為字符串類型,則依下表取得 tag,然后返回 “[object ” + tag + “]” 形式的字符串。

      新標(biāo)準(zhǔn)引入了 [Symbol.toStringTag] 屬性,是為了把此方法接口化,用于規(guī)范新引入的對(duì)象對(duì)此方法的調(diào)用。但對(duì)于“老舊”的對(duì)象,就只能直接輸出值,以保證兼容性。

      // 1. 三個(gè)容器對(duì)象。這類對(duì)象用作命名空間,用于存儲(chǔ)同一類方法。JSON[Symbol.toStringTag]; // => “JSON”Math[Symbol.toStringTag]; // => “Math”Atomics[Symbol.toStringTag]; // => “Atomic”// 這三個(gè)對(duì)象的 toString() 都沒有重寫,直接調(diào)用 toString() 方法也可以得到相同的結(jié)果。JSON.toString(); // => “[object JSON]”Math.toString(); // => “[object Math]”Atomics.toString(); // => “[object Atomics]”// 2. 兩個(gè)新引入的類型 BigInt 和 Symbol。BigInt.prototype[Symbol.toStringTag]; // => “BigInt”Symbol.prototype[Symbol.toStringTag]; // => “Symbol”// 3. 四個(gè)集合(Collection)對(duì)象。Set.prototype[Symbol.toStringTag]; // => “Set”Map.prototype[Symbol.toStringTag]; // => “Map”WeakSet.prototype[Symbol.toStringTag]; // => “WeakSet”WeakMap.prototype[Symbol.toStringTag]; // => “WeakMap”// 4. 在不同的實(shí)現(xiàn)中,有些第三方對(duì)象也部署了此屬性。// 比如在瀏覽器中:Window.prototype[Symbol.toStringTag]; // => “Window”HTMLElement.prototype[Symbol.toStringTag]; // => “HTMLElement”Blob.prototype[Symbol.toStringTag]; // => “Blob”// 5. 模塊命名空間對(duì)象(Module Namespace Object)。// 新引入的模塊命名空間對(duì)象(Module Namespace Object)也是部署了此屬性的。import * as module from “./export.js”;module[Symbol.toStringTag]; // => “Moduel”// 6. 在 Node.js 中g(shù)lobal[Symbol.toStringTag]; // => “global”

      我們?cè)賮砜匆幌?Object 以及其原型上的 toString 方法:

      Object.toString(); // “function Object() { [native code] }”Object.prototype.toString(); // “[object Object]”var o = new Object();console.log(o.toString()); // 返回 [object Object]console.log(o.__proto__.toString()); // 返回 [object Object]console.log(o.__proto__.toString === Object.prototype.toString); // true

      我們可以看出 Object 和它的原型鏈上各自有一個(gè) toString 方法,Object 輸出的是其函數(shù)體 “function Object() { [native code] }”,而 Object 原型上輸出的是其類型 “[object Object]”。

      數(shù)據(jù)類型

      例子

      輸出

      字符串

      “foo”.toString()

      “foo”

      數(shù)字

      1.toString()

      Uncaught SyntaxError: Invalid or unexpected token

      布爾值

      true.toString()

      “true”

      undefined

      undefined.toString()

      Uncaught TypeError: Cannot read property ‘toString’ of undefined

      null

      null.toString()

      Uncaught TypeError: Cannot read property ‘toString’ of null

      String

      String.toString()

      “function String() {[native code]}”

      Number

      Number.toString()

      “function Number() {[native code]}”

      Boolean

      Boolean.toString()

      “function Boolean() {[native code]}”

      Array

      Array.toString()

      “function Array() {[native code]}”

      Function

      Function.toString()

      “function Function() {[native code]}”

      Date

      Date.toString()

      “function Date() {[native code]}”

      RegExp

      RegExp.toString()

      “function RegExp() {[native code]}”

      Error

      Error.toString()

      “function Error() {[native code]}”

      Promise

      Promise.toString()

      “function Promise() {[native code]}”

      Object

      Object.toString()

      “function Object() {[native code]}”

      Math

      Math.toString()

      “[object Math]”

      Window

      Window.toString()

      “function Window() { [native code] }”

      window

      window.toString()

      “[object Window]”

      數(shù)據(jù)類型調(diào)用 toString() 方法的返回值,由此我們看出不同的數(shù)據(jù)類型都有其自身toString()方法

      // Boolean 類型,tag 為 “Boolean”console.log(Object.prototype.toString.call(true)); // => “[object Boolean]”// Number 類型,tag 為 “Number”console.log(Object.prototype.toString.call(1)); // => “[object Boolean]”// String 類型,tag 為 “String”console.log(Object.prototype.toString.call(“”)); // => “[object String]”// Array 類型,tag 為 “String”console.log(Object.prototype.toString.call([])); // => “[object Array]”// Arguments 類型,tag 為 “Arguments”console.log(Object.prototype.toString.call((function() { return arguments;})())); // => “[object Arguments]”// Function 類型, tag 為 “Function”console.log(Object.prototype.toString.call(function(){})); // => “[object Function]”// Error 類型(包含子類型),tag 為 “Error”console.log(Object.prototype.toString.call(new Error())); // => “[object Error]”// RegExp 類型,tag 為 “RegExp”console.log(Object.prototype.toString.call(/d+/)); // => “[object RegExp]”// Date 類型,tag 為 “Date”console.log(Object.prototype.toString.call(new Date())); // => “[object Date]”// 其他類型,tag 為 “Object”console.log(Object.prototype.toString.call(new class {})); // => “[object Object]”// window 全局對(duì)象console.log(Object.prototype.toString.call(window); // => “[object Window]”)

      在 JavaScript 中,所有類都繼承于 Object,因此 toString 方法應(yīng)該也被繼承了,但由上述可見事實(shí)并不像我們想的那樣,其實(shí)各數(shù)據(jù)類型使用 toString() 后的結(jié)果表現(xiàn)不一的原因在于:所有類在基礎(chǔ) Object 的時(shí)候,改寫了 toString 方法。盡管如此,但 Object 原型上的方法是可以輸出數(shù)據(jù)類型的,因此我們想判斷數(shù)據(jù)類型時(shí),也只能使用原型上的 toString 方法:Object.prototype.toString.call(object) 。

      直接調(diào)用

      toString(); // “[object Undefined]”(function(){ console.log(toString()); // [object Undefined]})();也就是說直接調(diào)用toString()方法,等價(jià)于Object.prototype.toString.call(); // “[object Undefined]”Object.prototype.toString.call(undefined); // “[object Undefined]”即:直接調(diào)用 toString() 方法這里不可以理解成為全局作用域調(diào)用 toString() 方法,即 window.toString()所以直接調(diào)用 toString() 應(yīng)該就是變相的 undefined.toString() 方法(這里說的是相當(dāng)于,實(shí)際 undefined 并沒有方法,調(diào)用會(huì)報(bào)錯(cuò))。

      驗(yàn)證

      // 定義一個(gè)數(shù)組var arr = [1, 2, 3]// 數(shù)組原型上是否具有 toString() 方法console.log(Array.prototype.hasOwnProperty(‘toString’)) //true// 數(shù)組直接使用自身的 toString() 方法console.log(arr.toString()) // ‘1,2,3’// delete操作符刪除數(shù)組原型上的 toString()delete Array.prototype.toString// 刪除后,數(shù)組原型上是否還具有 toString() 方法console.log(Array.prototype.hasOwnProperty(‘toString’)) //false// 刪除后的數(shù)組再次使用 toString() 時(shí),會(huì)向上層訪問這個(gè)方法,即 Object 的 toString()console.log(arr.toString()) // ‘[object Array]’

      當(dāng)我們把 Array 自身的 toString() 方法刪除之后,再次使用它時(shí),由原型鏈它會(huì)向上查找這個(gè)方法,即 Object 的 toString(),也便將 Object 上的 toString() 方法作用在數(shù)組上,得出其數(shù)據(jù)類型 [object Array] 。

      為什么需要call/apply

      經(jīng)常有人用 toString.call/apply(類型) 去代替 Object.prototype.toString.call/apply(類型) 使用,其實(shí)這樣是不嚴(yán)謹(jǐn)?shù)?,容易?dǎo)致一些問題,如下所示

      function toString(){ console.log(“1”)}toString(); // 1toString.call({}); // 1toString.call([]); // 1

      我們可以發(fā)現(xiàn),當(dāng)我們自定義了 toString() 方法時(shí),直接調(diào)用 toString() 方法,就不會(huì)再默認(rèn)調(diào)用 Object 類的 toString() 方法,而是會(huì)使用我們自定義的方法,這樣可能得不到我們想要的結(jié)果,所以我們還是應(yīng)當(dāng)盡量使用 Object.prototype.toString.call/apply(類型)。

      正因?yàn)?Object.prototype.toString() 本身允許被重寫,像 Array、Boolean、Number 的 toString 就被重寫過,所以需要調(diào)用 Object.prototype.toString.call(arg) 或 Object.prototype.toString.apply(arg) 或 Reflect.apply() 來判斷 arg 的類型,call 將 arg 的上下文指向 Object,所以 arg 執(zhí)行了 Object 的 toString() 方法。

      至于 call,就是改變對(duì)象的 this 指向,當(dāng)一個(gè)對(duì)象想調(diào)用另一個(gè)對(duì)象的方法,可以通過 call 或者 apply 改變其 this 指向,將其 this 指向擁有此方法的對(duì)象,就可以調(diào)用該方法了。

      var x = { toString() { return “X”; },};x.toString(); // => “X”Object.prototype.toString.call(x); // => “[object Object]”Object.prototype.toString.apply(x); // => “[object Object]”Reflect.apply(Object.prototype.toString, x, []); // => “[object Object]”

      判斷原生JSON對(duì)象

      var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON);console.log(isNativeJSON); // 輸出結(jié)果為 “[object JSON]” 說明JSON是原生的,否則不是;

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
      用戶投稿
      上一篇 2022年6月14日 09:10
      下一篇 2022年6月14日 09:11

      相關(guān)推薦

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息