1. 程式人生 > 其它 >JS/TS 中的 null 和 undefined 的區別

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?
var
str2: 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 這個梗的來源