JS/TS 中的 null 和 undefined 的區別
最近把一個小專案由js逐步改成了ts, 空安全這個概念也復現出, 之前寫js也沒有留意這個, 然後一開始很迷惑他倆的區別, 想著既然已經有 null 了為什麼還要 undefined呢?
然後跳回到ObjC 去對比 nil 和 NSNull.null 然後竟然豁然開朗了
然後對比了下Java又, 理解更深刻了些;
先說Java
public class Main { public static void main(String[] args) { // write your code here String str; System.out.println(str); } }
這段程式碼在java中是編譯不通過的, 因為str未進行初始化
這裡可以給 str 賦值 null 或者 ""
但是賦值 null 的時間也帶來了另外一個問題, java的空指標異常
我就在想, 如果良好的編碼習慣是否可以避免空指標異常呢?
回到js程式碼中
let obj console.log(obj?.length) console.log(typeof obj)
這段程式碼的執行結果是什麼呢
兩個 undefined
這裡也提到一個 js 的 ?. 操作符 如果沒有 ? 這個程式也是要異常的
因為沒有對 obj 初始化, 那麼可以理解為他的值就是 undefined
在ObjC中物件沒有初始化那麼就是 nil
第一個undefined是 obj沒有屬性 lenght ("TypeError: Cannot read properties of undefined (reading 'length')")
第二個undefined是obj的型別是 undefined
其實寫到這裡我又懷疑自己了, undefined到底是空值呢還是一種特殊的型別呢?
我們應該養成一種好的編碼喜歡, 給變數初始化, 避免 null undefined nil
objc中的nil還好, 呼叫方法不會異常, 但是其他語言就不一樣了
後來的Swift專門針對null進行了優化, 就是可選繫結與解包, 程式碼如下
var str1: String? varstr2: String! var str3: String print(str1!) print(str2) print(str3)
swift和ts也能簡單對應上,
先說上面的程式碼是編譯不過的, 因為沒有對 str3進行初始化, str定義為不允許為nil的 String 型別
然後還會有執行時錯誤(即崩潰)
這是為什麼呢? 因為str1 定義為可以為nil, 但是你使用的時間就要注意了, str1! 為強制解包, 但是 str1 此時就是 nil, 解包失敗必然崩, 其實看了ts中對 ! 的定義為 "非空斷言" 也是一個不錯的理解思路
str2 會出現警告, 其實 str1 和 str2 本質是一樣的, 結合"非空斷言"這個概念就更好理解了,
因為在我們的開發中肯定會存在建構函式中不對其進行初始化, 但是用的時間一定會有值的情況, 所以增加了這種就可以讓我們使用的時間可以直接"非空斷言", 會方便一些;
那麼對上面的程式碼進行優化便是
var str1: String? var str2: String! var str3: String = "str3" str2 = "str2" if let str = str1 { print(str) } print(str2!) print(str3)
程式碼執行結果是 str2 str3
如果不對str2進行賦值的話程式也會執行時異常, 核心: 非空斷言
然後回到JS問題本身,
首先我們應該儘量避免程式碼中出現null, 特別在ts中
允許的話就要對變數進行初始化, 如果不能進行初始化型別就要加一個 | undefined
不允許的話就指定型別然後初始化
寫到這裡我更加確定 在 js 中 undefined 是一種型別, 而他有一個 undefined 的值
如果變數不賦值, 那麼就是 undefined 型別?
這樣理解是不是好接受一點
另外插一句
js中應該避免使用 "==" 來比較
需要使用 "=== " 來避免強制型別轉化的比較
這也是為什麼 [] == false [] == true 這個梗的來源