Javascript學習筆記-強制類型轉換

Javascript類型轉換.png

1. 基本類型轉換

由于Javascript中存在七種基本類型:number, string , boolean , object, null, undefined, symbol,在使用過程中會有意識和無意識的在 運行時 存在相互轉換。

1.1 toString

1.1.1 較大數和較小數

當數字處于較大或較小時,由于Javascript會將數字轉換為科學記數法方式記錄,這個時候如果對其進行轉換為字符串,那么顯示結果是科學記數法的字符串

console.log(String(0.0000000001)); // '1e-10'
console.log(String(10000000000000000000000)); // '1e+22'
1.1.2 對象的toString

一般對象的toString方法,將會顯示該對象的[[class]]

Object.prototype.toString.call({}); // '[object Object]'
Object.prototype.toString.call(function(){}) // '[object Function]'
1.1.3 數組的toString

數組由于自身重寫過toString方法,數組的toString方法會返回逗號連接的字符串

Array.prototype.toString.call(['1', 'a', {'a': 1}]); // '1,a,[object Object]'
1.1.4 JSON.stringify()

JSON.stringify()方法用于將數據轉換為JSON格式的字符串,但是對于undefined, function, symbol類型的數據,在轉換時會選擇拋棄,從而返回undefined

JSON.stringify(undefined); // undefined
JSON.stringify(function(){}); // undefined
JSON.stringify(Symbol('test')); // undefined

轉換對象在數組中時,這些值會被賦值為null

JSON.stringify([undefined, 1, function(){}]); // [null, 1, null]    

如果轉換對象出現循環引用,那么在轉換的時候會拋出異常。
為了使得我們所有的對象在轉換成JSON字符串的時候可以正常轉換,我們可以定義toJSON方法,該方法在JSON.stringify調用前會進行調用,對數據進行處理

var a = {a: 1, b: 2};
a.toJSON = function() {
    return {a: 1}
}
JSON.stringify(a); // "{"a": "1"}"

JSON.stringify一共可以接受三個參數,除了第一個參數為轉換對象以外,第二個參數可以接收了一個數組或者方法對轉換對象屬性進行過濾,第三個參數則可以將JSON字符串進行格式化

var a = {a: 1, b: 2};
// 第二個參數使用數組進行過濾
JSON.stringify(a, ['a']); // "{"a": "1"}"
// 第二個參數使用function,自身對象會先調用方法一次后,每個屬性調用一次,返回undefined時則過濾掉該屬性
JSON.stringify(a, (k, v)=>{
    if (k!=='a') {
      return v;
    }
}); // "{"b": 2}"
// 第三個參數進行格式化,接收數字時每個層級添加相應數目空格
JSON.stringify({a:1, b:2, c: {a: 1}}, null, 2);
// 第三個參數如果為字符串,則每個層級添加該字符串,能添加的字符串最大長度為10
JSON.stringify({a:1, b:2, c: {a: 1}}, null, '--');

1.2 toNumber

1.2.1 基本類型轉Number

基本類型轉為number,按照以下規則轉換:

// null , false , '' 轉換為0
console.log(Number(null)); // 0
console.log(Number(false)); // 0
console.log(Number('')); // 0
// true轉換為1
console.log(Number(true)); // 1
// undefined轉換為NaN 
console.log(Number(undefined)); // NaN
// 字符串如果是數字格式則會進行轉換
console.log(Number('123')); // 123
1.2.2 對象轉Number

遵循toPrimitive的規則,如果對象存在valueOf方法,則調用該方法,如果調用后返回的結果為基本類型,則按照 1.2.1 基本類型轉Number 規則進行轉換;如果返回不為基本類型或者不存在valueOf方法,則調用toString方法后,按照 1.2.1 基本類型轉換Number 規則進行處理

var a = [1]; 
// 轉為Number,首先使用a.valueOf()方法,返回[1] 
// 繼續調用toString方法,返回'1' 
// 再將字符串轉為數字1
console.log(Number(a)); // 1
// 如果重寫valueOf方法,則會返回超乎想象的結果
a.valueOf = () => {return 2};
console.log(Number(a)); // 2

1.3 toBoolean

boolean類型轉換過程只會進行真假值的檢查,其中假值包括: false, '', null, undefined, NaN, +0, -0,假值將會轉換為false,假值以外的其他值均為真值,轉換為true

console.log(Boolean(false)); // false
console.log(Boolean('')); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(+0)); // false
console.log(Boolean(-0)); // false

1.4 特殊

對于一個特殊的對象Object.create(null),由于原型鏈的繼承關系,該對象不繼承Object,所以不存在valueOftoString方法,那么在進行轉換的時候將拋出異常

var a = Object.create(null);
console.log(Number(a)); // Uncaught TypeError: Cannot convert object to primitive value

2. 類型轉換

類型轉換可以分為顯示類型轉換和隱式類型轉換,但顯示和隱式只是相對的,在我們知道會進行轉換的時候他就是隱式,當我們知道會進行轉換以后其實就變為了顯式轉換了。

2.1 顯示類型轉換

2.1.1 String()和Number()轉換

按照 1. 基本類型轉換 的toString和toNumber的規則進行轉換

2.1.2 一元運算符轉換

使用一元運算符(+, -)會將數據轉換為number類型,相當于Number(data)

console.log(+[]); // 0 ,使用toNumber的規則,相當于Number([])
2.1.3 位反運算符轉換

使用位反運算符(~)會將數據轉換為number類型,相當于-(Number(data) + 1)

console.log(~[]); // -1

利用位反運算符,可以一些特定方法返回值進行處理后,簡化判斷

// 例如indexOf匹配失敗會返回-1,就可以利用位反運算簡化判斷條件
if('abc'.indexOf('a') > -1) {}
// 相當于
if(~'abc'.indexOf('a')){}
2.1.4 字符串解析

使用parseIntparseFloat可以將字符串(非字符串會優先轉換為字符串)解析為number類型,不同于Number()的強制類型轉換,解析過程會進行到不能解析為止,而Number()轉換在判斷不能轉換到時候直接返回NaN

console.log(parseInt('12ab')); // 12
console.log(Number('12ab')); // NaN

在ES5以后,parseInt默認使用了10進制作為基數進行轉換,可以通過第二個參數指定基數,此時對字符串解析過程會按照指定進制進行

console.log(parseInt('1a', 19)); // 29 因為按照19進制1和a都是有效的字符,返回結果為29
2.1.5 !轉換

使用'!',可以轉換為boolean類型,轉換相當于Boolean(data)

console.log(!0); // true
console.log(!!0); //false
2.1.6 Symbol()對象轉換

Symbol對象不能通過隱式轉換進行,如果要進行轉換必須使用構造方法來顯示轉換(似乎只能轉為字符串)。

var a = Symbol('1');
console.log(a + 1); Uncaught TypeError: Cannot convert a Symbol value to a number
console.log(String(a) + 1); // 'Symbol(1)1'

2.2 隱式類型轉換

2.2.1 算數運算轉換

在算數運算的過程中會進行數據轉換:
對于+運算來說,如果兩個操作數中存在字符串,則會嘗試進行字符串連接操作,如果操作數為對象,則會使用toPrimitive(使用valueOf方法和toString方法)轉為基本類型后,再進行判斷。如果不存在字符串,則全部轉為數字進行加法操作。

console.log(1 + ['1']); // 11 , 先將對象['1']根據toPrimitive規則轉為'1',操作變為 1 + '1' , 進行字符串拼接

對于-運算來說,直接將所有操作數進行toNumber操作后進行計算

console.log(1 - ['1']); // 0
2.2.2 邏輯語句中的類型轉換

作為邏輯語句中的判斷條件,將轉換為boolean值進行處理

if(1) { console.log(1)}; //  由于Boolean(1)是true,所以會打印1
if(0) { console.log(1)}; //  由于Boolean(0)是false,所以不會打印1
2.2.3 ||和&&

||&&的操作,返回結果并不是boolean值,而是根據短路規則,判斷操作數的Boolean()結果,返回兩個操作數的其中之一,其中||true時進行短路返回,&&false時進行短路返回

var a = 1 && 0;
console.log(a); // 0 , 由于第一個操作數Boolean(1)是true,所以返回第二個操作數
a = 0 && 1; 
console.log(a); // 0 , 由于第一個操作數Boolean(0)是false,所以返回第一個操作數
a = 1 || 0; 
console.log(a); // 1, 由于第一個操作數Boolean(1)是true,所以返回第一個操作數
a = 0 || 1; 
console.log(a); // 1, 由于第一個操作數Boolean(0)是false,所以返回第二個操作數

3. 數據比較

3.1 寬松等于

使用==進行比較的稱做寬松等于,區別于===的嚴格等于,在于進行比較的時候,等式兩邊的數值在類型不相等的時候會嘗試進行強制轉換,而嚴格等于不會進行類型的轉換。
寬松等于的轉化規則如下:

  • 如果兩個比較數類型一致且為基本類型,則直接進行比較,數字按照大小,字符串按照字母表順序比較。
  • 如果兩個比較數類型不一致且為基本類型,則轉換為number進行比較。
  • 如果兩個比較數據均為對象類型,則比較對象的引用是否相等
  • 如果兩個數據中一個為對象,則根據toPrimitive規則,將其轉換為基本類型后,進行比較。

console.log('a' == 'a'); // true , 類型相同且為基本類型,則直接比較
console.log('1' == 1); // true , 類型不同但均為基本類型,將'1'轉為number進行比較
console.log({} == {}); // false , 兩個比較數均為對象,判斷引用是否相等
console.log('a' == ['a']); // true,一個比較數為對象,則將['a']轉換為'a'后進行比較

對于特殊的undefinednull

console.log(undefined == null); // true

3.2 抽象比較

抽象比較也就是非等于比較,比較規則和寬松等于規則相同

console.log('a' < 'b'); // true, 類型相同,直接進行比較,字符串按照字母表順序
console.log('0' < 1); // true, 類型不同但均未基本類型,將'0'轉為number后進行比較
console.log('a' < ['b']); // true, 一個比較數為對象,則將['b']轉換為'b'后進行比較

4. 參考

《你不知道的Javascript(中卷)》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容