こんにちは、Yuriです。
今回は、最近学んだJavaScriptの小さなTipsとして、オブジェクトの分割代入とオプショナルチェーンを整理します。
オブジェクトの分割代入
オブジェクトの分割代入を使うと、プロパティの値を取り出して変数へ代入できます。
const user = {
greeting: 'Hello',
farewell: 'Bye',
}
const { greeting, farewell } = user
console.log(greeting) // 'Hello'
console.log(farewell) // 'Bye'
ネストしたプロパティを取り出す
オブジェクトの中にオブジェクトがある場合は、データの構造に合わせて分割代入のパターンもネストできます。
const user = {
greeting: 'Hello',
message: {
farewell: 'Bye',
},
}
const {
greeting,
message: { farewell },
} = user
console.log(greeting) // 'Hello'
console.log(farewell) // 'Bye'
この例で作られる変数はgreetingとfarewellです。messageは、内側のfarewellへたどるためのパターンとして使われているだけなので、変数として宣言されません。
console.log(message)
// ReferenceError: message is not defined
const { message } = user
const { farewell } = message
プロパティ名とは異なる変数名で受け取る
コロンの右側へ名前を書くと、プロパティ名とは異なる変数名で値を受け取れます。
const user = {
name: 'Yuri',
}
const { name: userName } = user
console.log(userName) // 'Yuri'
この場合もnameという変数は作られず、作られるのはuserNameです。
オプショナルチェーン(?.)
オプショナルチェーンは、参照の途中にある値がnullまたはundefinedだった場合、エラーを発生させずにundefinedを返す演算子です。
const user = {
name: 'Yuri',
}
console.log(user.profile?.hobby) // undefined
user.profileはundefinedですが、?.を使っているため、その先のhobbyへアクセスせず評価を終了します。
通常のプロパティアクセスではエラーになります。
console.log(user.profile.hobby)
// TypeError: Cannot read properties of undefined
配列の要素へアクセスする
角括弧によるアクセスでは、?.[]の形で使用します。
const items = [
{ name: 'Item 1' },
{ name: 'Item 2' },
]
console.log(items[1]?.name) // 'Item 2'
console.log(items[3]?.name) // undefined
const emptyItems = undefined
console.log(emptyItems?.[0]) // undefined
関数やメソッドを呼び出す
関数が存在するときだけ呼び出したい場合は、?.()を使用します。
const actions = {
greet: () => 'Hello',
}
console.log(actions.greet?.()) // 'Hello'
console.log(actions.sayGoodbye?.()) // undefined
プロパティが存在していても、その値が関数でなければTypeErrorになります。?.()は「呼び出し可能かどうか」まで確認するものではありません。
DOM要素へアクセスする
querySelectorは対象が見つからなかった場合にnullを返します。要素が存在するときだけプロパティを参照したい場合にも利用できます。
const button = document.querySelector('.sample-button')
console.log(button?.textContent) // 要素がなければundefined
短絡評価される範囲
オプショナルチェーンでは、左側がnullまたはundefinedの場合、そのチェーンの残りは評価されません。
let index = 0
const items = null
const item = items?.[index++]
console.log(item) // undefined
console.log(index) // 0
ただし、オプショナルチェーンが途切れた後のアクセスは保護されません。
const user = null
user?.profile.name // undefined
(user?.profile).name // TypeError
括弧で区切ると、その後の.nameは別のプロパティアクセスとして評価されます。
??と組み合わせて既定値を設定する
オプショナルチェーンで取得した結果がnullまたはundefinedだった場合、ヌル値合体演算子(??)で既定値を設定できます。
const user = {}
const hobby = user.profile?.hobby ?? '未設定'
console.log(hobby) // '未設定'
||は0、空文字列、falseも右側の値へ置き換えますが、??が右側を返すのはnullまたはundefinedの場合だけです。
オプショナルチェーンを使うときの注意点
オプショナルチェーンは条件分岐を簡潔にできますが、必須であるはずの値にまで使用すると、不具合をundefinedとして見逃す可能性があります。
次のように使い分けることが大切です。
- 値が存在しないことを仕様として許容する場合は
?.を使う - 値が必須の場合は明示的に確認し、存在しなければエラーとして扱う
- 取得結果に既定値が必要な場合は
??を組み合わせる
まとめ
ネストした分割代入を使うと、深い階層の値を簡潔に変数へ取り出せます。ただし、途中のプロパティ名がそのまま変数になるわけではありません。
オプショナルチェーンを使うと、nullやundefinedの可能性があるプロパティ、配列、関数へ安全にアクセスできます。便利さだけで多用せず、その値が本当に省略可能なのかを考えて使っていきたいです。


