必考知識點-JavaScript類型轉換(講原理)

1、類型轉換先說類型

類型轉換指將一種類型轉換爲另外一種類型,那咱們首先來講說JavaScript中的類型。html

1.1原始(Primitive)數據類型

  • Null
  • Undefined
  • Boolean
  • String
  • Number
  • Symbol
  • BigInt

BigInt是一種新的數據類型,用於當整數值大於Number數據類型支持的範圍時。這種數據類型容許咱們安全地對大整數執行算術操做,表示高分辨率的時間戳,使用大整數id,等等,而不須要使用庫。 重要的是要記住,不能使用Number和BigInt操做數的混合執行算術運算,須要經過顯式轉換其中的一種類型。 此外,出於兼容性緣由,不容許在BigInt上使用一元加號(+)運算符。 java

1.2引用(Object)數據類型

javaScript中內置了不少對象。面試

  • Array
  • Array
  • ArrayBuffer
  • AsyncFunction
  • Atomics
  • BigInt
  • BigInt64Array
  • BigUint64Array
  • Boolean
  • DataView
  • Date
  • Error
  • EvalError
  • Float32Array
  • Float64Array
  • Function
  • Generator
  • GeneratorFunction
  • Infinity
  • Int16Array
  • Int32Array
  • Int8Array
  • InternalError
  • Intl
  • Intl.Collator
  • Intl.DateTimeFormat
  • Intl.ListFormat
  • Intl.Locale
  • Intl.NumberFormat
  • Intl.PluralRules
  • Intl.RelativeTimeFormat
  • JSON
  • Map
  • Math
  • NaN
  • Number
  • Object
  • Promise
  • Proxy
  • RangeError
  • ReferenceError
  • Reflect
  • RegExp
  • Set
  • SharedArrayBuffer
  • String
  • Symbol
  • SyntaxError
  • TypeError
  • TypedArray
  • URIError
  • Uint16Array
  • Uint32Array
  • Uint8Array
  • Uint8ClampedArray
  • WeakMap
  • WeakSet
  • WebAssembly
  • decodeURI()
  • decodeURIComponent()
  • encodeURI()
  • encodeURIComponent()
  • escape()
  • eval()
  • globalThis
  • isFinite()
  • isNaN()
  • null
  • parseFloat
  • parseInt
  • undefined
  • unescape()
  • uneval()

詳情請參考MDN安全

你們不要看javaScript的內置對象這麼多,轉換時只須要把這麼通通當作一個類型引用類型進行轉換就行,在javaScript內部中轉換也不會考慮這麼多。 bash

2、自動裝箱

爲了方便操做基本數據類型, ECMAScript還提供了三個特殊的引用類型,基本包裝類型,String、Boolean、Number。有了這三個類型,在須要的時候,原始類型會自動轉換成相應的包裝對象(這個過程叫自動裝箱)。自動裝箱就是臨時建立一個包裝對象,將原始類型的值封裝起來,以便調用包裝對象的函數。可是原來那個變量的值不會有任何變化! ide

var s1 = "some text";
var s2 = s1.substring(2);
複製代碼

字符串是基本數據類型,爲撒能調用方法了,這其實在後臺進行了一系列的操做函數

  1. 建立String類型的一個實例
  2. 在實例上調用指定的方法。
  3. 銷燬這個實例。
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
複製代碼

固然,你能夠將Boolean 、Number 、String 這三個函數看成構造函數來使用,經過手動new包裝類來裝箱(獲得包裝對象):ui

// 手動裝箱
var s1 = new String("some text");  
s1.toUpperCase();
typeof s1;  
// "object"
複製代碼

3、類型轉換的規則

4、內部用於實現類型轉換的4個函數

4.1 ToPrimitive ( input [ , PreferredType ] )

// ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
// (1) for number hint, and (2) for string hint.
function ToPrimitive(x, hint) {
    // Fast case check.
    if (IS_STRING(x)) return x;
    // Normal behavior.
    if (!IS_SPEC_OBJECT(x)) return x;
    if (IS_SYMBOL_WRAPPER(x)) throw MakeTypeError(kSymbolToPrimitive);
    if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
    return (hint == NUMBER_HINT) ? DefaultNumber(x) : DefaultString(x);
}

// ECMA-262, section 8.6.2.6, page 28.
function DefaultNumber(x) {
    if (!IS_SYMBOL_WRAPPER(x)) {
        var valueOf = x.valueOf;
        if (IS_SPEC_FUNCTION(valueOf)) {
            var v = % _CallFunction(x, valueOf);
            if (IsPrimitive(v)) return v;
        }
        var toString = x.toString;
        if (IS_SPEC_FUNCTION(toString)) {
            var s = % _CallFunction(x, toString);
            if (IsPrimitive(s)) return s;
        }
    }
    throw MakeTypeError(kCannotConvertToPrimitive);
}

// ECMA-262, section 8.6.2.6, page 28.
function DefaultString(x) {
    if (!IS_SYMBOL_WRAPPER(x)) {
        var toString = x.toString;
        if (IS_SPEC_FUNCTION(toString)) {
            var s = % _CallFunction(x, toString);
            if (IsPrimitive(s)) return s;
        }
        var valueOf = x.valueOf;
        if (IS_SPEC_FUNCTION(valueOf)) {
            var v = % _CallFunction(x, valueOf);
            if (IsPrimitive(v)) return v;
        }
    }
    throw MakeTypeError(kCannotConvertToPrimitive);
}
複製代碼

ToPrimitive將input裝換爲基本數據類型,PreferredType要麼不傳,要麼是number、string。spa

4.1.1 PreferredType爲number

  1. 若是input自己就是原始類型,直接返回input。
  2. 調用input.valueOf(),若是結果是原始類型,則返回這個結果。
  3. 調用input.toString(),若是結果是原始類型,則返回這個結果。
  4. 拋出TypeError異常。

4.1.2 PreferredType爲string

  1. 若是input自己就是原始類型,直接返回input。
  2. 調用input.toString(),若是結果是原始類型,則返回這個結果。
  3. 調用input.valueOf(),若是結果是原始類型,則返回這個結果。
  4. 拋出TypeError異常。

4.1.3 PreferredType不傳入

  1. 若是input是內置的Date類型,PreferredType 視爲String
  2. 不然PreferredType 視爲 Number。

來看看這道網上的面試題3d

({}) + 1
複製代碼

+號操做符,只有當左右兩邊的類型相同(都爲string或者number)是才進行操做。因此會經歷以下步驟:

  1. {}和1都會調用ToPrimitive,1原始類型直接返回。
  2. {}內部調用DefaultNumber,使用valueOf方法,返回object。
  3. 在調用toString方法,返回[object, object]。
  4. 因此最後的結果就是[object, object]1。

這一類轉換換湯不換藥,轉換規則都是這樣的。

4.2 ToBoolean ( argument )

4.3 ToNumber( argument )

4.4 ToString( argument )

來源:ECMA-262草案/ 2019年11月7日 ECMAScript®2020語言規範

5、隱式類型裝換

在執行過程當中當js內部指望獲得某種類型的值,而實際在那裏的值是其餘的類型,就會發生隱式類型轉換。系統內部會自動調用咱們前面說ToBoolean ( argument )、ToNumber ( argument )、ToString ( argument ),嘗試轉換成指望的數據類型。

5.1 指望獲得boolean的值

if ( !undefined && !null && !0 && !NaN && !'') {
  // xxxx
} 
複製代碼

由於在if的括號中,js指望獲得boolean的值,因此對括號中每個值都使用ToBoolean ( argument ),將它們轉化成boolean。

5.2 指望獲得number的值

3 * { valueOf: function () { return 5 } }; 
複製代碼

由於在乘號的兩端,js指望獲得number類型的值,因此對右邊的那個對象使用ToNumber ( argument ),獲得結果5,再與乘號左邊的3相乘。

5.3 加號有別於其餘運算符

  • 若是有一邊是字符串,就把另一邊也轉換爲字符串
  • 若是一方不是字符串或者數據,就轉換爲數據或者字符串

處了加號運算符,其餘運算符,只要其中一方數據,那麼另外一方就被轉換爲數字

6、顯示類型裝換

手動調用Boolean(value)、Number(value)、String(value)完成的類型轉換。

Boolean('some text');  //  true
Number("2019");  //  2019
String({a: 1});  //  "[object Object]"
複製代碼

前面兩個類型轉換沒有什麼好解釋的,咱們看看最後一個String({a: 1});在內部發生的時候

  1. 執行轉換String({a: 1})。
  2. 執行內部的ToString({a: 1})。
  3. {a: 1}不是原始類型,執行ToPrimitive({a: 1}, hint string)。
  4. 調用toString方法,返回"[object, object]"。
  5. 執行ToString("[object, object]"),返回"[object, object]"。

參考文章:

相關文章
相關標籤/搜索