Jeff的隨手筆記

學習當一個前端工程師

0%

『JavaScript 基礎』Coercion

Imgur

這是一門在Udemy 課程,是同學介紹的。主要是因為想要運用到過年前這段時間好好的增進自己的JavaScript的基礎能力,讓自己能往前端工程師更近一步。主要還是會以筆記的形式做呈現!


coercion指的是將資料從一種型態轉換成另一種型態,在某些情況下JavaScript會根據它自己的判斷將資料轉換成另一種型式。

1
2
3
var a = 1 + '2';
console.log(a) // 12
console.log(typeof a) // string

在實作過程中有時候會發生我把兩個不同型別的變數做運算,這個時候JavaScript 會在執行的過程中會去猜測你的程式碼是什麼意思,因此當他看到了數字 + 字串時,他會自己判斷為你可能是要2個字串連接起來,所以他會把1從number強制轉換成 string,所以才會出現12。
所以這個時候,當我們用 typeof 來查看型別時就會發現,a 的型別已經變成了string了

了解了什麼是coercion之後,我們來看看下一個練習:

1
console.log(3 < 2 < 1)

按照我們的數學基礎這題的答案應該會是false,但實際結果卻是true。

為什麼會變成這樣?一樣我們一步一步拆解:
首先先比較3 < 2 ,這個答案會是false,接下來再把得到的結果去跟後面的比就會變成false < 1。
疑,這時候發現兩邊型別不同耶,所以JavaScript 引擎就會執行Coercion,把boolean轉換成number,因此false就會變轉換成0,所以false < 1 會變成 0 < 1,因此出來的結果會是true

因此當我們看到另一個題目 console.log(1 < 2 < 3)出來的結果為true時,並不要開心太早,因為不是我們數學知識認為的那樣,而是因為小於的associativity為左到右,因此會先比較1 < 2然後再比較 true < 3。因為型別不一樣執行Coercion,把true轉換成1,所以console.log(1 < 2 < 3)結果才會是true。

看到這裡 boolean 會被強制轉換,我還蠻好奇其他被強制轉換成number會變成怎樣,來看一下其他Primitive type被強制轉換會變成什麼吧。

1
2
3
4
5
console.log("false:", Number(false));
console.log('true:', Number(true));
console.log("string 3:", Number('3'));
console.log("undefined:", Number(undefined));
console.log("null:", Number(null));

輸出結果為:

1
2
3
4
5
false: 0
true: 1
string 3: 3
undefined: NaN
null: 0

這時候發現一個很有趣的地方了,undefined會被轉換成 NaN 也就是 not a number,但null卻是會被轉換成0。

這也就是會導致很多奇怪錯誤的地方,尤其是在我們在使用if時。
因此我們會在if中加入條件時,例如當什麼什麼等於什麼什麼的時候,在其他語言都是用雙等號,但是因為JavaScript 的Coercion特性,在JavaScript裏面當我們要去判斷2個東西是否一樣時我們會用3個等號也就是“===”

既然提到if,那就不能提到boolean,在判斷是裡面我們也常會使用到,先來看看其他Primitive type在什麼時候被強制轉換會變成false。

1
2
3
4
console.log("string '':", Boolean("")); //false
console.log("undefined:", Boolean(undefined)); //false
console.log("null:", Boolean(null)); //false
console.log("number 0:", Boolean(0)); //false

由上面結果我們可以得知,空字串、數字0、undefined、null都會被轉換成false

那我們來看看下面這段code,我想要的結果是:當今天只要有任何值就必須印出:Something is there

1
2
3
4
var a;
if (a) {
console.log(Something is there)
}

由上面的輸出結果我得知,當今天變數是空字串、undefined 跟null 時,他的boolean會是false
因此這段code執行後不會印出任何東西,但這不是如我想要的,因此當我把code變成這樣:

1
2
3
4
var a = 任何數字或字串;
if (a) {
console.log(Something is there)
}

雖然這樣我們可以完成我們的要求,但因為上面我們測試過,當Boolean(0)時會回傳false這時候我們就不能只是單純這樣寫,因為有可能我們會輸入0,因此要改成:

1
2
3
4
var a = 任何數字或字串;
if (a || a === 0) {
console.log(Something is there)
}

這樣就可以了


接下來要提到默認值,先看一下下面的code:

1
2
3
4
5
6
function greet(name) {
name = name || '<Your name here>';
console.log('Hello ' + name);
}

greet('Tony');

這就是剛剛提到的默認值。
也就是當這個函式沒有傳入我們需要的參數時,他就會使用第二個值。
之所以可以這樣用是因為 Short-circuit evaluation中(||)的特性:如果當第1個運算子為”falsy”時,則回傳第2個運算子。否則,將會回傳第1個運算子。
但這邊有一個地方要特別記住,要小心0。
另外ES6有導入新的方法:

1
2
3
function greet(name = '<Your name here>') {
console.log('Hello ' + name);
}

這樣的語法會比之前的預設值語法來得更佳簡單明確,除此之外,傳入參數預設值它與之前使用短路求值的作法有一個最大的不同之處:
只有在傳入參數為undefined時或是不存在,才會使用預設值