[課程筆記]克服JS的奇怪部分-CH2 型別與運算子

Udemy課程連結
課程總目錄

本篇筆記目錄:

觀念小叮嚀:型別與Javacript
U8 純值
觀念小叮嚀:運算子
U9 運算子的優先性與相依性
觀念小叮嚀:強制型轉
U10 比較運算子
U11 存在與布林
U12 預設值
框架小叮嚀:預設值

觀念小叮嚀:型別與Javacript

JS 是 Dynamic Typing

Dynamic Typing 動態型別

我們不需要告訴 JS 你的變數是何種型別的資料,相反地,它會在運行程式時自動知道,所以當你執行程式時,一個變數可以在不同時候擁有不同型別,因為型別都是在執行時才知道的!

其他程式語言像 Java 或 C# 它們用靜態型別的方式處理,一開始就要告訴編譯器你的變數是什麼資料行別,


U8 純值

純值是一種資料的型別,表示一個值,換句話說,不是物件

JS 有六種純值(primitive types,或稱基本型別)

  1. undefined
  2. null
  3. boolean
  4. number:為一個數值型態,它是浮點數(永遠有小數點在後面)
  5. string
  6. sybmol:ES6 新增的純值

觀念小叮嚀:運算子

運算子是一個特殊的函數,通常需要兩個參數來回傳一個值

a+c如何運作?可以想成這樣:

//+ 是函數名稱
function +(a,c){
	return //add the two number
}

+(a,c)

但這樣寫太麻煩,所以和大部分的程式語言一樣,我們只需要使用中綴表示法(將函數名稱寫在兩個參數之間)

//拿掉括號和逗號,將函數名稱寫在兩個參數之間
a+c

U9 運算子的優先性與相依性

Precendence 優先性

在同一行不只有一個運算子時,哪個運算子被優先運算

var a=3+4*5
console.log(a)

//23

具有高優先性的會優先運算,
+ 為13 * 為14
*大於+,所以 4*5 先執行然後回傳20 ,然後執行 3+20 再回傳23

運算子優先表鏈結

括號為優先性為19,所以裡面的東西永遠最先計算

Associativity 相依性

當運算子優先性相同時,運算子被計算的順序

左到右的相依性:左相依性
右到左的相依性:右相依性

var a=2
var b=3
var c=4
a=b=c
console.log(a);
console.log(b);
console.log(c);

//4
//4
//4

為什麼會輸出4呢?因為 = 的相依性為 右相依性,所以會先執行 b=c 並回傳 4,再執行 a=4, 回傳 4!


觀念小叮嚀:強制型轉

Coercion 強制行轉

轉換一個值的型別(例:數值轉成字串)

var a=1+'2'
console.log(a)

//12
//第一個數值被強制行轉成字串

U10 比較運算子

console.log(1<2<3)
//true

console.log(3<2<1)
//true

為何第二個回傳true 呢?
1.「 <」為左相依性,所以從左開始看起

  1. 3<2 回傳 false,false<1,出現非預期型別,boolean 值被強制型轉

我們可以使用 Number() 觀察,Number() 可以將東西轉換成數值

Number('3')
//3
Number('false')
//0
Number('true')
//1

會發現 boolean 值會被強制型轉成 1 和 0
所以當 false<1 時,實際執行的是 0<1,回傳 true

我們回頭再看console.log(1<2<3),1<2 回傳true ,true<3 是1<3 回傳 true

其他強制型轉的情況:

Number(undefined)
//NaN:代表無法轉換成數值

Number(null)
//0

因為強制型轉的關係,我們會很難除錯,像是:

var a= false;
a==0
//true

""==0
//true

""==false
//true

所以99%時間我們會使用 = (strict equality) 來比較相等性,它會同時判斷型別是否相同

3=3
//true

3==='3'
//false

U11 存在與布林

所有不存在的東西都會被轉換成 null

Boolean(undefined)
//false

Boolean(null)
//false

Boolean("")
//false

Boolean("hi")
//true

而我們可以利用這個特性去檢查東西是否存在

var a;
//code to find a's value

if(a){
	console.log('sth is here')
}

在 if 陳述句括號裡面的東西,它會試著轉換為布林,如果最後a是undefined(因為中間未設值),或是 null,”“,我們都會得到回傳的false

但有個要注意的地方 Boolean(0) 也會回傳 false,所以我們可以寫成這樣,判斷是否為0

var
//code to find a's value

if(a||a===0){
	console.log('sth is here')
}

U12 預設值

不同於其他程式語言,JS 在我們沒有放入參數時,不會丟出錯誤訊息!

function greet(name){
	console.log(name)
	console.log('hello'+name);
}

greet()

//undefined
//Hello undefined

執行過程:

  1. greet() 被呼叫,一個新的執行環境被創造
  2. JS 忽略了我們沒有用參數呼叫這個函數,name 在記憶體中被設定為 undefined
  3. undefined 被強制轉型為字串,然後被和”hello”放在一起

如果我們想要一個設一個預設值給這個參數呢?

ES6 中有可以設定預設值的方法:

function green(name='jack'){
	console.log('Hello'+name)
}

green();

但在舊的方法中我們可以這麼使用:

function greet(name){
name= name||'<Your name here>'
console.log('hello'+name);
}

greet()

//'hello <Your name here>'

為什麼呢?因為 || 不只是回傳 true 或 false ,它還可會回傳可以被強制轉型為true的值:

true||false
//true

undefined||'hello'
//'hello'
//當他非 boolean 值時,回傳可以被強制轉型為true的值

'hi'||'hello'
//'hi'
//當他非 boolean 值時,回傳第一個可以被強制轉型為true的值

所以我們回頭看這行

name= name||'<Your name here>'

當 name 可以被強制轉型為true 時,回傳 name,如果 name 是 undefined 時,回傳 '<Your name here>'


框架小叮嚀:預設值

我們已經學過的東西如何應用在受歡迎的框架中?
假設lib1和lib2是我的兩個框架:

<script src="lib1.js></srcipt>
<script src="lib2.js></srcipt>
<script src="app.js></srcipt>

//lib1.js(假裝一個libary)
var libaryName='Lib 1'

//lib2.js(假裝另一個libary)
var libaryName='Lib 2'

//app.js
console.log(libaryName)
//'Lib 2'

這三個 script 標籤不會創造新的執行環境,它們會把程式碼堆在對方上面,結合和最小化你的JS程式成為一個檔案,再執行,所以 libaryName 會被視為全域環境的全域變數,在Lib2.js中被重新附值。

這在框架中很不尋常,可能會讓我框架互相衝突

解決方法:

測試libaryName是否已經在全域執行環境、全域變數裡

//lib2.js
window.libaryName=window.libaryName||'Lib 2'