古詩詞大全網 - 藝術簽名 - JS的類型怎麽轉換

JS的類型怎麽轉換

這次給大家帶來JS的類型怎麽轉換,JS類型轉換的註意事項有哪些,下面就是實戰案例,壹起來看壹下。

隱式類型轉換

在 JavaScript 中,當我們進行比較操作或者加減乘除四則運算操作時,常常會觸發 JavaScript 的隱式類型轉換機制;而這部分也往往是令人迷惑的地方。譬如瀏覽器中的 console.log 操作常常會將任何值都轉化為字符串然後展示,而數學運算則會首先將值轉化為數值類型(除了 Date 類型對象)然後進行操作。

我們首先來看幾組典型的 JavaScript 中運算符操作結果,希望閱讀完本部分之後能夠對每壹個條目都能進行合理解釋:

// 比較

[] == ![] // true

NaN !== NaN // true

1 == true // true

2 == true // false

"2" == true // flase

null > 0 // false

null < 0 // false

null == 0 // false

null >= 0 // true

// 加法

true + 1 // 1

undefined + 1 // NaN

let obj = {};

{} + 1 // 1,這裏的 {} 被當成了代碼塊

{ 1 + 1 } + 1 // 1

obj + 1 // [object Object]1

{} + {} // Chrome 上顯示 "[object Object][object Object]",Firefox 顯示 NaN

[] + {} // [object Object]

[] + a // [object Object]

+ [] // 等價於 + "" => 0

{} + [] // 0

a + [] // [object Object]

[2,3] + [1,2] // '2,31,2'

[2] + 1 // '21'

[2] + (-1) // "2-1"

// 減法或其他操作,無法進行字符串連接,因此在錯誤的字符串格式下返回 NaN

[2] - 1 // 1

[2,3] - 1 // NaN

{} - 1 // -1

原始類型間轉換

JavaScript 中我們常說的原始類型包括了數值類型、字符串類型、布爾類型與空類型這幾種;而我們常用的原始類型之間的轉換函數就是 String、Number 與 Boolean:

// String

let value = true;

console.log(typeof value); // boolean

value = String(value); // now value is a string "true"

console.log(typeof value); // string

// Number

let str = "123";

console.log(typeof str); // string

let num = Number(str); // becomes a number 123

console.log(typeof num); // number

let age = Number("an arbitrary string instead of a number");

console.log(age); // NaN, conversion failed

// Boolean

console.log( Boolean(1) ); // true

console.log( Boolean(0) ); // false

console.log( Boolean("hello") ); // true

console.log( Boolean("") ); // false

最終,我們可以得到如下的 JavaScript 原始類型轉換表(包括復合類型向原始類型轉換的範例):

原始值

轉化為數值類型

轉化為字符串類型

轉化為 Boolean 類型

false

0

"false"

false

true

1

"true"

true

0

0

"0"

false

1

1

"1"

true

"0"

0

"0"

true

"1"

1

"1"

true

NaN

NaN

"NaN"

false

Infinity

Infinity

"Infinity"

true

-Infinity

-Infinity

"-Infinity"

true

""

0

""

false

"20"

20

"20"

true

"twenty"

NaN

"twenty"

true

[ ]

0

""

true

[20]

20

"20"

true

[10,20]

NaN

"10,20"

true

["twenty"]

NaN

"twenty"

true

["ten","twenty"]

NaN

"ten,twenty"

true

function(){}

NaN

"function(){}"

true

{ }

NaN

"[object Object]"

true

null

0

"null"

false

undefined

NaN

"undefined"

false

ToPrimitive

在比較運算與加法運算中,都會涉及到將運算符兩側的操作對象轉化為原始對象的步驟;而 JavaScript 中這種轉化實際上都是由 ToPrimitive 函數執行的。實際上,當某個對象出現在了需要原始類型才能進行操作的上下文時,JavaScript 會自動調用 ToPrimitive 函數將對象轉化為原始類型;譬如上文介紹的 alert 函數、數學運算符、作為對象的鍵都是典型場景,該函數的簽名如下:

ToPrimitive(input, PreferredType?)

為了更好地理解其工作原理,我們可以用 JavaScript 進行簡單地實現:

var ToPrimitive = function(obj,preferredType){

var APIs = {

typeOf: function(obj){

return Object.prototype.toString.call(obj).slice(8,-1);

},

isPrimitive: function(obj){

var _this = this,

types = ['Null','Undefined','String','Boolean','Number'];

return types.indexOf(_this.typeOf(obj)) !== -1;

}

};

// 如果 obj 本身已經是原始對象,則直接返回

if(APIs.isPrimitive(obj)) {return obj;}

// 對於 Date 類型,會優先使用其 toString 方法;否則優先使用 valueOf 方法

preferredType = (preferredType === 'String' || APIs.typeOf(obj) === 'Date' ) ? 'String' : 'Number';

if(preferredType==='Number'){

if(APIs.isPrimitive(obj.valueOf())) { return obj.valueOf()};

if(APIs.isPrimitive(obj.toString())) { return obj.toString()};

}else{

if(APIs.isPrimitive(obj.toString())) { return obj.toString()};

if(APIs.isPrimitive(obj.valueOf())) { return obj.valueOf()};

}

throw new TypeError('TypeError');

}

我們可以簡單覆寫某個對象的 valueOf 方法,即可以發現其運算結果發生了變化:

let obj = {

valueOf:() => {

return 0;

}

}

obj + 1 // 1

如果我們強制將某個對象的 valueOf 與 toString 方法都覆寫為返回值為對象的方法,則會直接拋出異常。

obj = {

valueOf: function () {

console.log("valueOf");

return {}; // not a primitive

},

toString: function () {

console.log("toString");

return {}; // not a primitive

}

}

obj + 1

// error

Uncaught TypeError: Cannot convert object to primitive value

at <anonymous>:1:5

值得壹提的是對於數值類型的 valueOf() 函數的調用結果仍為數組,因此數組類型的隱式類型轉換結果是字符串。而在 ES6 中引入 Symbol 類型之後,JavaScript 會優先調用對象的 [Symbol.toPrimitive] 方法來將該對象轉化為原始類型,那麽方法的調用順序就變為了:

當 obj[Symbol.toPrimitive](preferredType) 方法存在時,優先調用該方法;

如果 preferredType 參數為 String,則依次嘗試 obj.toString() 與 obj.valueOf() ;如果 preferredType 參數為 Number 或者默認值,則依次嘗試 obj.valueOf() 與 obj.toString() 。

而 [Symbol.toPrimitive] 方法的簽名為:

obj[Symbol.toPrimitive] = function(hint) {

// return a primitive value

// hint = one of "string", "number", "default"

}

我們同樣可以通過覆寫該方法來修改對象的運算表現:

user = {

name: "John",

money: 1000,

[Symbol.toPrimitive](hint) {

console.log(`hint: ${hint}`);

return hint == "string" ? `{name: "${this.name}"}` : this.money;

}

};

// conversions demo:

console.log(user); // hint: string -> {name: "John"}

console.log(+user); // hint: number -> 1000

console.log(user + 500); // hint: default -> 1500

比較運算

JavaScript 為我們提供了嚴格比較與類型轉換比較兩種模式,嚴格比較(===)只會在操作符兩側的操作對象類型壹致,並且內容壹致時才會返回為 true,否則返回 false。而更為廣泛使用的 == 操作符則會首先將操作對象轉化為相同類型,再進行比較。對於 <= 等運算,則會首先轉化為原始對象(Primitives),然後再進行對比。

標準的相等性操作符(== 與 !=)使用了Abstract Equality Comparison Algorithm來比較操作符兩側的操作對象(x == y),該算法流程要點提取如下:

如果 x 或 y 中有壹個為 NaN,則返回 false;

如果 x 與 y 皆為 null 或 undefined 中的壹種類型,則返回 true(null == undefined // true);否則返回 false(null == 0 // false);如果 x,y 類型不壹致,且 x,y 為 String、Number、Boolean 中的某壹類型,則將 x,y 使用 toNumber 函數轉化為 Number 類型再進行比較;如果 x,y 中有壹個為 Object,則首先使用 ToPrimitive 函數將其轉化為原始類型,再進行比較。

我們再來回顧下文首提出的 [] == ![] 這個比較運算,首先 [] 為對象,則調用 ToPrimitive 函數將其轉化為字符串 "";對於右側的 ![],首先會進行顯式類型轉換,將其轉化為 false。然後在比較運算中,會將運算符兩側的運算對象都轉化為數值類型,即都轉化為了 0,因此最終的比較結果為 true。在上文中還介紹了 null >= 0 為 true 的這種比較結果,在 ECMAScript 中還規定,如果 < 為 false,則 >= 為 true。

加法運算

對於加法運算而言,JavaScript 首先會將操作符兩側的對象轉換為 Primitive 類型;然後當適當的隱式類型轉換能得出有意義的值的前提下,JavaScript 會先進行隱式類型轉換,再進行運算。譬如 value1 + value2 這個表達式,首先會調用 ToPrimitive 函數將兩個操作數轉化為原始類型:

prim1 := ToPrimitive(value1)

prim2 := ToPrimitive(value2)

這裏將會優先調用除了 Date 類型之外對象的 valueOf 方法,而因為數組的 valueOf 方法的返回值仍為數組類型,則會返回其字符串表示。而經過轉換之後的 prim1 與 prim2 中的任壹個為字符串,則會優先進行字符串連接;否則進行加法計算。

相信看了本文案例妳已經掌握了方法,更多精彩請關註Gxl網其它相關文章!

推薦閱讀: