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