Sitemap
Johnny Fang

Johnny Fang

這是我在軟體工程之旅所看見的風景 | email: johnny781222@gmail.com | LinkedIn: www.linkedin.com/in/johnny-fang-9356b2156

[JavaScript] Optional Chaining Operator 可選串連運算子

啊是可以取值了沒

9 min readAug 30, 2025

--

最後更新時間:2025–08–30

Press enter or click to view image in full size
沒找到喜歡的圖,Unsplash 竟然沒有彩色鎖鏈,只好放個很陽光的鎖鏈 | Photo by Janosch Diggelmann on Unsplash

前言

這個運算子其實已經用 N 次了,但一直有個小困擾,決定寫篇文章並且想個辦法來加深印象。(好像很少寫這麼短的前言?)

說文解字

這次要選哪個字呢好像沒哪個字特別奇怪,好啦選個 chaining 好了,chaining 是動詞 chain 的現在分詞、動名詞,來看看 chain 這個字在劍橋字典的解釋,依序是名詞與動詞:

a set of connected events, usually where one causes the next

to fasten someone or something using a chain

chain 如果當名詞會有一個個串起來的意思,若當動詞則有用鏈條把東西綁起來的感覺,來練習造個句:

I chained the dragon to the doorway of the room to keep cockroaches from crawling in.

翻譯:我把龍鎖在房間門口以防止小強爬進來。

Optional Chaining Operator 簡介

先看一下這段程式碼:

let fruit = null
console.log(fruit.cherry)

若執行這段程式碼會看到這行 error:

TypeError: Cannot read properties of null (reading 'cherry')

如果把 fruit 賦值為 undefined 也會有類似的 error msg:

TypeError: Cannot read properties of undefined (reading 'cherry')

如果 fruit.cherry 取不到值並非什麼大不了的事而希望程式碼不要報錯,那可以怎麼做?聰明的工程師們就想出了「?.」的做法,物件取值最常見的應該類似以下這樣,第一種是原本寫法、第二種則是加入可選串連運算子後的寫法:

// 一般寫法
console.log(cart.fruit.apple)
// optional chaining
console.log(cart?.fruit?.apple)

Optional Chaining Operator 這個運算子的名稱也挺好理解的,原本取值就像是鎖鏈一樣把 cart、fruit、apple 串連起來,而加個 optional 就有點可有可無的那種感覺,有的話就串連起來沒有就回傳個 undefined 這樣。

當然,物件內的函式也可以這樣用,例如:

let fruit = {
apple: 10,
banana: 20,
cherry: { specialPrice: 13},
sayHello() {
console.log('Hello fruit')
return 'hey hey'
}
}
fruit.sayHello() // 印出 Hello fruit
console.log(fruit.sayHello()) // 印出 Hello fruit 跟 hey hey

但如果這樣寫:

let fruit = null
fruit?.sayHello() // 什麼事也不會發生
console.log(fruit?.sayHello()) // 印出 undefined

本篇文章為了方便舉例就不用函式只用一般取值來說明。

Optional Chaining Operator 是在 ES2020 釋出的,有興趣可以去 ECMA 找 Standards,例如到這個頁面,找 ECMA-262, 11th edition, June 2020,看到 12.3.9 Optional Chains 的章節。如果你好奇 ECMA、誰去制定等等問題,可以看這篇。

對了,如果仔細看 MDN 會發現上面說:

The optional chaining (?.) operator accesses an object’s property or calls a function. If the object accessed or function called using this operator is undefined or null, the expression short circuits and evaluates to undefined instead of throwing an error.

這邊寫「object’s property」複習一下,property、key、value 分別指的是什麼呢?先來一籃水果:

let fruit = {
apple: 10,
banana: 20,
cherry: 30,
}
  • property:就是一組 key value pair,利如「apple: 10」、「banana: 20」
  • key:像是 apple、banana、cherry
  • value:10、20、30

順便複習基本觀念,不錯吧。

以前怎麼用?現在怎麼用?

Get Johnny Fang’s stories in your inbox

Join Medium for free to get updates from this writer.

先假設我有這些水果:

let fruit = {
apple: 10,
banana: 20,
cherry: { specialPrice: 13}
}
console.log(fruit.date.specialPrice)

如果想看 date(椰棗)的特殊價格,那就會出錯:

TypeError: Cannot read properties of undefined (reading 'specialPrice')

很正常,因為 fruit 裡面沒有 date,導致 fruit.date 是 undefined,再針對 undefined 取值就報錯了,所以以前如果想確保有 property 再取值,可能會想要這樣寫:

let fruit = {
apple: 10,
banana: 20,
cherry: { specialPrice: 13}
}
if (fruit && fruit.date) {
console.log(fruit.date.specialPrice)
}
console.log("啥事都沒發生")

一看就知道很冗,如果用可選串連運算子就會方便很多:

let fruit = {
apple: 10,
banana: 20,
cherry: { specialPrice: 13}
}
console.log(fruit?.date?.specialPrice)
console.log("啥事都沒發生")

如果上面這樣寫 console 會印出什麼:

undefined
啥事都沒發生

也就是說,不會報錯只會印出 undefined

不會報錯,豈不美哉

是嗎?

如果這麼好,為什麼還要保留原本的報錯機制?

會不會好奇,既然都有可選串連運算子了幹嘛不把這個功能設計為預設,也就是每當取值時如果取值對象是 null 或 undefined 就不報錯直接回傳 undefined 就好了?

要回答這個問題可以思考,假設先不管什麼運算子,單純就想,為什麼程式要有報錯機制?

大概有以下幾項:

  • 早期發現錯誤:若沒報錯那錯誤只會變成錯誤數值或怪異行為,開發者很難察覺
  • 避免錯誤傳染:小錯誤如果不攔下來可能一路傳到更深的邏輯或外部系統,例如一個 undefined 如果沒處理可能最後導致金額是 NaN 或 undefined,使用者直接黑人問號
  • 提供偵錯訊息:可以看 error msg 找線索是哪一行出錯
  • 強化程式可靠性:嚴格的錯誤處理能讓系統在壞掉時「明確壞掉」而不是「偷偷壞掉」,如果偷偷壞掉那真的是很壞吶

因此,下個問題會變成,什麼情境要用、什麼情境則建議別用可選串連運算子?

用與不用的情境

🟢 適合使用

  • 資料來源不保證完整:API 回傳內容可能缺欄位、使用者輸入的資料可能為空
let apiRes = {}; console.log(apiRes.user?.profile?.age); // undefined,不報錯
  • 物件層級很深:避免寫一堆 && 判斷
// 傳統寫法
if (obj && obj.user && obj.user.address) {
console.log(obj.user.address.city);
}
// optional chaining
console.log(obj?.user?.address?.city);
  • 屬性是選填或可選的:不在乎缺少時的錯誤,只要安全取值
let config = { darkMode: true };
console.log(config.settings?.theme); // undefined

❌ 不適合使用

  • 這個值理論上必須存在:例如必填欄位、邏輯核心資料
let user = null;
console.log(user?.id); // undefined
// 錯誤被吃掉,可能造成後續邏輯出錯
// 應該讓它報錯,幫助偵錯
// 想想看,萬一 user id 會用在超多地方結果默默地變成 undefined,恐怖唷
  • 需要精確錯誤訊息時:例如寫 library 或 SDK,要讓使用者清楚知道缺少參數

關於開頭提到的小困擾

就是……有時會忘記問號是在左邊還是右邊 😂,先別急著噴我,這是個很廢的困擾我知道,但不解決就癢癢的而且說不定哪天你也會打錯,因此除了寫篇文章外我還想了口訣,對,就跟以前老師在教八國聯軍是哪八國時都會說如果俄德法美日奧義英記不起來就記「餓的話每日熬一鷹」一樣,雖可恥,但有效

我想的口訣是:

不問就取會悲劇,先問再取能繼續

如果不寫問號直接取值可能會發生悲劇,但如果先寫問號再取值就能讓程式繼續運行而不會因為報錯而中斷。這個口訣的設計是讓「問」都在「取」前面,自然會記得先寫問號,而且想一想好像也是欸,先問一下再拿東西比較有禮貌吧?(三小)

結尾

想了個不怎樣的口訣後趕緊進入結尾才不會丟臉太久。寫這篇只是想幫我自己,如果有人有一樣的小困擾我會很驚訝,就跟以前寫過一篇 新注音打字練習大進擊 一樣,原本只是分享如何改善自己堪稱家族恥辱的打字速度沒想到卻意外地不少人看。

對了有篇文章寫得還不錯,使用可選串連運算子時還能搭配 Nullish Coalescing 打出 combo 技,有興趣可以參考:前端開發 🦏 來談 JavaScript 的 Optional Chaining 和 Nullish Coalescing (一)。總之,為了解決小困擾而寫的本文如果有順便幫到你的話就太棒了。

--

--