摘要:相對(duì)于顯式使用,隱式轉(zhuǎn)換則更加簡(jiǎn)潔。隱式轉(zhuǎn)換為布爾值將其他類型值隱式轉(zhuǎn)換為布爾值是我們最常用的一種轉(zhuǎn)換。在以下場(chǎng)景中,都是進(jìn)行判斷,而只要傳入的值不是布爾值,都會(huì)通過(guò)隱式類型轉(zhuǎn)換轉(zhuǎn)為布爾值。原文地址阿木木的博客與隱式鴨子類型轉(zhuǎn)換
前言
說(shuō)實(shí)話,JavaScript 的類型轉(zhuǎn)換是個(gè)相當(dāng)頭疼的問(wèn)題,無(wú)論是對(duì)于初學(xué)者還是有經(jīng)驗(yàn)的老司機(jī)。它的難處并不在于概念多難理解,而是情況多且雜,看似相同的情況結(jié)果卻又出人意料,很少有人能保證時(shí)刻都能做出正確的判斷。
因此,這篇文章希望能講的足夠細(xì)致和明確,讓大家能夠在日常使用中,能夠盡快的搞清楚類型轉(zhuǎn)換的順序和結(jié)果。
長(zhǎng)文預(yù)警,建議先 mark, 分多次查看。
一、類型轉(zhuǎn)換 1. 什么叫類型轉(zhuǎn)換?我們知道,JavaScript 中存在七種數(shù)據(jù)類型,在必要的時(shí)候,我們會(huì)對(duì)不同類型的值進(jìn)行相互間的轉(zhuǎn)換。比如說(shuō),在進(jìn)行條件判斷時(shí),我們需要將其他類型的值轉(zhuǎn)為布爾類型值,在使用 console.log() 打印內(nèi)容時(shí),需要將其轉(zhuǎn)為字符串輸出。
2. JavaScript 中的類型轉(zhuǎn)換方式有哪些?在 JavaScript 中,分為顯式類型轉(zhuǎn)換和隱式類型轉(zhuǎn)換。
其中,顯式類型轉(zhuǎn)換是我們?yōu)榱斯δ苄枰藶榈膶⒁环N類型的值轉(zhuǎn)換為另一中類型,轉(zhuǎn)換的時(shí)機(jī)和結(jié)果都是我們預(yù)期的;而隱式類型轉(zhuǎn)換則是 JavaScript 在代碼運(yùn)行時(shí),未經(jīng)我們?cè)试S而進(jìn)行的強(qiáng)制類型轉(zhuǎn)換。
二、顯式類型轉(zhuǎn)換 1. 其他類型轉(zhuǎn)換為字符串( ToString )值類型 | 例子 | 轉(zhuǎn)換后 | 調(diào)用法則 |
---|---|---|---|
number | 34 | "34" | String(34) |
boolean | true | "true" | String(true) |
boolean | false | "false" | String(false) |
undefiend | undefined | "undefined" | String(undefined) |
null | null | "null" | String(null) |
object | { a: "fa" } | "[object Object]" | String({a: "fa"}) |
object | new String(45) | "45" | String(new String(45)) |
object | [1, 2] | "1,2" | String([1,2]) |
object | function() {var d;} | "function() { var d; }" | String(function() {var d;}) |
其他類型的值轉(zhuǎn)換為字符串,是通過(guò)調(diào)用原生函數(shù)String()實(shí)現(xiàn),但不同類型值的實(shí)現(xiàn)卻有明顯的差異。
對(duì)于基本類型的值,直接將其轉(zhuǎn)化為值的字符串形式。而對(duì)于對(duì)象類型來(lái)說(shuō),便有些復(fù)雜了。
首先,每個(gè)對(duì)象內(nèi)部都有一個(gè) [[Class]] 屬性,我們通過(guò)Object.prototype.toString() 方法可以得到這個(gè)屬性的字符串值。
對(duì)于對(duì)象(如{ a: "ff"; })而言,除非自己定義 toString() 方法,否則,調(diào)用 String() 方法將返回和調(diào)用 Object.prototype.toString() 相同的值。(如 : "[object Object]")。
const obj_1 = { b: "lalala" }; const obj_2 = { toString() { return "fasfa"; } }; String(obj_1); // "[object Object]" String(obj_2); // "fasfa"
其次, JavaScript 中,除了普通對(duì)象,還有以下幾種:
封裝對(duì)象
對(duì)于基本類型值 string、number、boolean 是沒(méi)有 .length 及toString() 方法的,因此,JavaScript 提供了內(nèi)建函數(shù) String()、Number()、Boolean() ,通過(guò) new 調(diào)用后會(huì)將基本類型值封裝為一個(gè)對(duì)象。
如果想要取到封裝對(duì)象中的基本類型值,可以使用 valueOf() 方法。
// string 類型 const a = "i am string"; typeof a; // "string" // string 封裝對(duì)象 const b = new String("i am sringObject"); typeof b; // "object" // 拆封 b.valueOf(); // i am sringObject
那對(duì)于封裝對(duì)象,String() 會(huì)返回什么值呢?
事實(shí)上,封裝對(duì)象對(duì)于 toString() 方法進(jìn)行了封裝,因此,對(duì)封裝對(duì)象調(diào)用 String() 方法,將會(huì)返回封裝對(duì)象調(diào)用toString() 方法返回的值。
const numObj = new Number(false); // Number {0} numObj.toString(); // "0" String(numObj); // "0"
函數(shù)
對(duì)于函數(shù)來(lái)說(shuō),它也包裝了自己的 toString()方法,因此,調(diào)用 String() 方法時(shí)將返回函數(shù)字符串化后的值。
function bar() { console.log("bar"); } String(bar); // "function bar() {? console.log("bar");?}" bar.toString(); // "function bar() {? console.log("bar");?}" Object.prototype.toString.call(bar); // "[object Function]"
從上例可以看到,String() 與 toString() 方法調(diào)用的是函數(shù)自己封裝的toSring(),如果調(diào)用對(duì)象的 toString() 方法,則函數(shù)與普通對(duì)象一樣,返回的是函數(shù)對(duì)象內(nèi)部的 [[Class]] 屬性。
數(shù)組
數(shù)組同函數(shù)一樣,同樣包裝了自己的 toString() 方法。此方法會(huì)將數(shù)組中的每一項(xiàng)用逗號(hào)連接成一個(gè)字符串。
const arr = [1,4,6]; String(arr); // "1,4,6" arr.toString(); // "1,4,6" Object.prototype.toString.call(arr); // "[object Array]"2. 其他類型值轉(zhuǎn)為數(shù)字( ToNumber )
同樣,先感受一下什么叫絕望?~~
值類型 | 例子 | 轉(zhuǎn)換后 | 調(diào)用法則 |
---|---|---|---|
string | "34" | 34 | Number("34") |
string | "" | 0 | Number("") |
string | "34fad" | NaN | Number("34fad") |
string | "34fad"、"34.24"、"34" | 34 | parseInt("34fad") |
string | "34fad"、"34" | 34 | parseFloat(值) |
string | "34.34" | 34.34 | parseFloat(值) |
boolean | true | 1 | Number(true) |
boolean | false | 0 | Number(false) |
undefiend | undefined | NaN | Number(undefined) |
null | null | 0 | Number(null) |
object | { a: "fa" } | NaN | Number({a: "fa"}) |
object | new String("fff") | NaN | Number(new String("fff")) |
object | [] | 0 | Number([]) |
object | [1, 2] | NaN | Number([1,2]) |
object | function() {var d;} | NaN | Number(function() {var d;}) |
看完一臉懵逼有沒(méi)有?!哈哈,不用害怕,乍看上去,大概會(huì)覺(jué)得異常混亂,其實(shí)稍加整理,不外乎以下幾種情況:
轉(zhuǎn)換后值為 NaN
數(shù)字與字符串不同,并不是任何類型值都能轉(zhuǎn)為數(shù)字,因此,就會(huì)有 NaN,意思就是 not a number。
諸如包含非數(shù)字的字符串、undefined、非空數(shù)組,部分對(duì)象,都是我們知道無(wú)法轉(zhuǎn)化為一個(gè)數(shù)字的。
boolean 類型值
對(duì)于 true和 false ,true 轉(zhuǎn)換為 1,false 轉(zhuǎn)為 0。
帶有數(shù)字的字符串
從上面我們可以看到,對(duì)于帶有數(shù)字的字符串,有三種方法進(jìn)行轉(zhuǎn)換,但規(guī)則不同。
Number() 方法會(huì)對(duì)字符串整體進(jìn)行轉(zhuǎn)換, 它會(huì)先判斷這個(gè)字符串是否是個(gè)正確的數(shù)字字符串,如果不是,則會(huì)返回 NaN。
parseInt() 方法則會(huì)對(duì)字符串從左往右依次解析,直到遇到第一個(gè)非數(shù)字字符(包括小數(shù)點(diǎn)),如果最左邊的字符是非數(shù)字字符,則返回 NaN。
parseFloat() 方法解析順序同 parseInt() 相同,不同的是它遇到第一個(gè)小數(shù)點(diǎn)時(shí)會(huì)正常往右繼續(xù)解析,直至遇到非數(shù)字字符停止。
其實(shí)嚴(yán)格來(lái)講,只有 `Number()` 方法是進(jìn)行轉(zhuǎn)換操作,而后兩者屬于將字符串**解析** 為數(shù)字,但為了講解方便,我將它們放在一起講述。
對(duì)象
對(duì)于對(duì)象而言,會(huì)先將對(duì)象轉(zhuǎn)為基本類型值( ToPrimitive ),再對(duì)基本類型值調(diào)用 Number() 方法。
那如何將對(duì)象轉(zhuǎn)為基本類型值?首先會(huì)調(diào)用對(duì)象的 valueOf() 方法,如果沒(méi)有此方法或者此方法返回值不是基本類型值,則會(huì)調(diào)用toString() 方法,如果 toString() 方法不存在或者返回值也不是基本類型值,會(huì)產(chǎn)生 TypeError 錯(cuò)誤。
// 普通對(duì)象 const nomalObj = { a: "56" }; nomalObj .valueOf(); // { a: "56"} nomalObj.toString(); // "[object Object]" // Number(nomalObj) 相當(dāng)于Number("[object Object]") Number("[object Object]"); // NaN Number(nomalObj); // NaN // valueOf() 返回基本類型值的對(duì)象 const obj_1 = { a: "56", valueOf: function() { return "23"; } }; obj_1.valueOf(); // "23" // Number(obj_1) 相當(dāng)于 Number("23"); Number("23"); // 23 Number(obj_1); // 23 // valueOf() 返回非基本類型值,toString() 返回基本類型值的對(duì)象 const obj_2 = { a: "56", valueOf: function() { return {b: 34} }, toString: function() { return false; } }; obj_2.valueOf(); // {b: 34} obj_2.toString(); // false // Number(obj_2) 相當(dāng)于 Number(false) Number(obj_2); // 0 Number(false); // 0
上面的規(guī)則,適用于我們所說(shuō)的所有對(duì)象,比如數(shù)組,封裝對(duì)象和函數(shù)。
3. 其他類型轉(zhuǎn)換為 boolean 值( ToBoolean )我們可以通過(guò) Boolean()方法 或!!運(yùn)算符來(lái)顯式的將一個(gè)值轉(zhuǎn)換為布爾值。
相對(duì)來(lái)說(shuō),判斷一個(gè)值是 true 還是 false 則比較容易,我們只需要記住以下幾種值會(huì)轉(zhuǎn)換為 false,而其他值,均為 true。
undefined
null
false
+0、-0 和 NaN
""
當(dāng)我們看到 []、{} 甚至是 """" 時(shí),也一定要記住,它們是真值。
Boolean(false); // fasle Boolean([]); //true Boolean({}); //true Boolean(""); // false Boolean(""""); // true Boolean("false"); // true三、隱式強(qiáng)制類型轉(zhuǎn)換
除了進(jìn)行強(qiáng)制類型轉(zhuǎn)換,JavaScript 會(huì)在運(yùn)行時(shí)根據(jù)需要,自動(dòng)進(jìn)行類型的轉(zhuǎn)換,盡管這個(gè)特點(diǎn)飽受爭(zhēng)議,但不得不承認(rèn),某些情況下我們?nèi)耘f更喜歡使用某些隱式轉(zhuǎn)換規(guī)則。
一旦某些隱式的規(guī)則被接受并廣泛使用,從某種意義上來(lái)講,這些規(guī)則便同顯式轉(zhuǎn)換一樣。
1. 奇怪的 + 號(hào)先看一一個(gè)最常見(jiàn)的例子:
const a = 5; const b = "6"; console.log(a+a); // 10 console.log(a+b); // "56" console.log(b+b); // "66"
之所以會(huì)產(chǎn)生上例中的狀況,原因就在于在JavaScript 中,+ 運(yùn)算符既可以作用于number 類型值,也可以作用于 string 類型值。前者進(jìn)行數(shù)字相加,后者則進(jìn)行字符串的拼接。
這就是為什么5 + 5 = 10 而 "6" + "6" = "66"。而當(dāng) + 號(hào)兩邊既有數(shù)字也有字符串時(shí),則會(huì)隱式的將數(shù)字轉(zhuǎn)換為字符串,然后進(jìn)行字符串的拼接。
那兩邊沒(méi)有字符串的情況呢?比如:
const a = [1,4]; const b = [2,3]; const c = 4; console.log(a+c); // "1,44" console.log(a+b); // "1,42,3"
為什么會(huì)這樣?原來(lái)只要 + 的其中一個(gè)操作數(shù)可以通過(guò)某種方式(toPrimitive)轉(zhuǎn)換為字符串,就會(huì)進(jìn)行字符串的拼接。
我們知道,數(shù)組[1,4] 可以通過(guò) toString() 方法返回字符串 "1,4",因此,[1,4] + 4 就相當(dāng)于 "1,4" + 4 。
因?yàn)檫@個(gè)特性,我們?cè)谙雽⒁粋€(gè)數(shù)字 a 轉(zhuǎn)換為字符串時(shí),便可以直接使用 a + "" 的形式即可。相對(duì)于顯式使用String(a),隱式轉(zhuǎn)換則更加簡(jiǎn)潔。
從數(shù)組的例子我們可以看到,除了數(shù)字,其他類型的值也可以通過(guò) + " " 的形式轉(zhuǎn)化為字符串。
const a = {b: "2"} console.log( a+ ""); // "[object Object]"
但有一點(diǎn)需要注意,對(duì)于對(duì)象而言,使用 String() 方法是直接取這個(gè)對(duì)象 toString() 方法的返回值,而 + " " ,則會(huì)對(duì)這個(gè)對(duì)象調(diào)用 valueOf 反法,然后對(duì) valueOf 的返回值調(diào)用 toString(),將其轉(zhuǎn)換為字符串。
const a = { toString: function() { return 45 }, valueOf: function() { return 4} }; String(a); // "45" a + " "; // // "4"
好在除非我們特意去改變一個(gè)對(duì)象的 valueOf 及 "toString()" 方法,通過(guò)上述兩個(gè)方式的轉(zhuǎn)換后的結(jié)果都是一致的。
2. 有用的 - 號(hào)與 + 號(hào)不同的是,- 號(hào)只能用于數(shù)字的相減,對(duì)于它兩邊的操作數(shù),都會(huì)經(jīng)過(guò)隱式類型轉(zhuǎn)換轉(zhuǎn)為數(shù)字。
const a = "34"; const b = "4"; console.log(a - b); // 30 const c = "dd"; console.log(a - c); // NaN const d = [4]; console.log(a - d); // 30
根據(jù)上例,我們可看到,如果 - 號(hào)兩邊是字符串,則會(huì)將他們強(qiáng)制轉(zhuǎn)換為數(shù)字,如果 - 兩邊不是字符串,則會(huì)先將其轉(zhuǎn)為字符串,再將這個(gè)字符串轉(zhuǎn)為數(shù)字。
3. 隱式轉(zhuǎn)換為布爾值將其他類型值隱式轉(zhuǎn)換為布爾值是我們最常用的一種轉(zhuǎn)換。因?yàn)槌绦虻木帉?xiě)實(shí)質(zhì)上就是不停的進(jìn)行判斷。
在以下場(chǎng)景中,都是進(jìn)行判斷,而只要傳入的值不是布爾值,都會(huì)通過(guò)隱式類型轉(zhuǎn)換轉(zhuǎn)為布爾值。
if (..) {} 語(yǔ)句中的條件判斷表達(dá)式。
for ( .. ; .. ; ..) 語(yǔ)句中的條件判斷表達(dá)式。
while (..) 和 do ... while ( ..) 中的條件判斷表達(dá)式。
? : 中的條件判斷表達(dá)式。
邏輯或 || 或邏輯與 && 左邊的操作數(shù)。
在這些情況下,都將會(huì)進(jìn)行其他類型值到布爾類型值的隱式轉(zhuǎn)換,規(guī)則同顯式調(diào)用 Boolean()。
完上面就是不同數(shù)據(jù)類型直接顯式或隱式的轉(zhuǎn)換規(guī)則,我們不需要將每一種情況都牢記在心,但有必要對(duì)他們進(jìn)行充分的了解,這可以保證我們?cè)趯?shí)際寫(xiě)代碼時(shí)避免不少奇怪又難以排查的 bug 。
原文地址:阿木木的博客 與 隱式 (鴨子)類型轉(zhuǎn)換)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/99850.html
摘要:本章我們來(lái)學(xué)習(xí)一下的基本數(shù)據(jù)類型與類型系統(tǒng)。字符串就是一個(gè)抽象數(shù)據(jù)類型。如果程序語(yǔ)言的語(yǔ)法中含有類型標(biāo)記,就稱該語(yǔ)言是顯式類型化的,否則就稱為隱式類型化的。但是,可以把中對(duì)應(yīng)的這幾種基本數(shù)據(jù)類型,理解為的基本類型的裝箱類。 第4章 基本數(shù)據(jù)類型與類型系統(tǒng) 《Kotlin極簡(jiǎn)教程》正式上架: 點(diǎn)擊這里 > 去京東商城購(gòu)買(mǎi)閱讀 點(diǎn)擊這里 > 去天貓商城購(gòu)買(mǎi)閱讀 非常感謝您親愛(ài)的讀...
摘要:同時(shí),有多個(gè)類級(jí)別的靜態(tài)構(gòu)造函數(shù)的方法。這個(gè)累贅,無(wú)論如何,是被傳遞到每個(gè)單獨(dú)的對(duì)象構(gòu)造函數(shù)表達(dá)式中。我們可能只有幾個(gè)特定的擔(dān)憂,提供額外關(guān)鍵字參數(shù)給構(gòu)造函數(shù)。 注:原書(shū)作者 Steven F. Lott,原書(shū)名為 Mastering Object-oriented Python 沒(méi)有__init__()的無(wú)狀態(tài)對(duì)象 下面這個(gè)示例,是一個(gè)簡(jiǎn)化去掉了__init__()的類。這是一個(gè)常見(jiàn)...
摘要:而的浮點(diǎn)數(shù)設(shè)置的偏移值是,因?yàn)橹笖?shù)域表現(xiàn)為一個(gè)非負(fù)數(shù),位,所以,實(shí)際的,所以。這是因?yàn)樗鼈冊(cè)谵D(zhuǎn)為二進(jìn)制時(shí)要舍入部分的不同可能造成的不同舍 IEEE 754 表示:你盡管抓狂、罵娘,但你能完全避開(kāi)我,算我輸。 一、IEEE-754浮點(diǎn)數(shù)捅出的那些婁子 首先我們還是來(lái)看幾個(gè)簡(jiǎn)單的問(wèn)題,能說(shuō)出每一個(gè)問(wèn)題的細(xì)節(jié)的話就可以跳過(guò)了,而如果只能泛泛說(shuō)一句因?yàn)镮EEE754浮點(diǎn)數(shù)精度問(wèn)題,那么下文還是...
摘要:一數(shù)據(jù)類型基本類型引用類型類型判斷返回結(jié)果未定義布爾值字符串?dāng)?shù)值對(duì)象或者函數(shù)拓展堆棧兩種數(shù)據(jù)結(jié)構(gòu)堆隊(duì)列優(yōu)先,先進(jìn)先出由操作系統(tǒng)自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。 一、數(shù)據(jù)類型 基本類型:`Null Boolean String Undefined Number(NB SUN)` 引用類型:`Array Function Object` 類型判斷:typeof 返回結(jié)果...
摘要:如果你能看懂以下兩張圖那就可以跳過(guò)本總結(jié)了當(dāng)然點(diǎn)個(gè)贊再走啊喂啊喂分割線你不知道的上冊(cè)作用域和閉包和查詢可以理解為查找變量賦值的目標(biāo)和源頭當(dāng)然賦值可以是隱晦的查詢失敗將在嚴(yán)格模式下導(dǎo)致拋出非嚴(yán)格模式下則會(huì)自動(dòng)創(chuàng)建新變量額分別是修改原有作用域和 如果你能看懂以下兩張圖, 那就可以跳過(guò)本總結(jié)了, 當(dāng)然, 點(diǎn)個(gè)贊再走啊喂! (#`O′)! showImg(https://segmentfau...
閱讀 2373·2021-11-24 10:26
閱讀 2565·2021-11-16 11:44
閱讀 1695·2021-09-22 15:26
閱讀 3565·2021-09-10 11:11
閱讀 3178·2021-09-07 10:25
閱讀 3615·2021-09-01 10:41
閱讀 1002·2021-08-27 13:11
閱讀 3498·2021-08-16 11:02