From 4f0b68dc75bdac5c31c68aac2a220ef58bbda684 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:04:02 +0700 Subject: [PATCH 1/8] Translate the "Objects: the basics" section to Thai and update constructor examples and return information --- .../07-optional-chaining/article.md | 219 +----------------- 1 file changed, 2 insertions(+), 217 deletions(-) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index f27f7d1d2..b6d6395e6 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -1,220 +1,5 @@ - -# Optional chaining '?.' +# Optional Chaining '?.' [recent browser="new"] -The optional chaining `?.` is a safe way to access nested object properties, even if an intermediate property doesn't exist. - -## The "non-existing property" problem - -If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common. - -As an example, let's say we have `user` objects that hold the information about our users. - -Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them. - -In such case, when we attempt to get `user.address.street`, and the user happens to be without an address, we get an error: - -```js run -let user = {}; // a user without "address" property - -alert(user.address.street); // Error! -``` - -That's the expected result. JavaScript works like this. As `user.address` is `undefined`, an attempt to get `user.address.street` fails with an error. - -In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street"). - -...and another example. In Web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element. - -```js run -// document.querySelector('.elem') is null if there's no element -let html = document.querySelector('.elem').innerHTML; // error if it's null -``` - -Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result. - -How can we do this? - -The obvious solution would be to check the value using `if` or the conditional operator `?`, before accessing its property, like this: - -```js -let user = {}; - -alert(user.address ? user.address.street : undefined); -``` - -It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. For more deeply nested properties, that becomes a problem as more repetitions are required. - -E.g. let's try getting `user.address.street.name`. - -We need to check both `user.address` and `user.address.street`: - -```js -let user = {}; // user has no address - -alert(user.address ? user.address.street ? user.address.street.name : null : null); -``` - -That's just awful, one may even have problems understanding such code. - -Don't even care to, as there's a better way to write it, using the `&&` operator: - -```js run -let user = {}; // user has no address - -alert( user.address && user.address.street && user.address.street.name ); // undefined (no error) -``` - -AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but also isn't ideal. - -As you can see, property names are still duplicated in the code. E.g. in the code above, `user.address` appears three times. - -That's why the optional chaining `?.` was added to the language. To solve this problem once and for all! - -## Optional chaining - -The optional chaining `?.` stops the evaluation if the value before `?.` is `undefined` or `null` and returns `undefined`. - -**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.** - -In other words, `value?.prop`: -- works as `value.prop`, if `value` exists, -- otherwise (when `value` is `undefined/null`) it returns `undefined`. - -Here's the safe way to access `user.address.street` using `?.`: - -```js run -let user = {}; // user has no address - -alert( user?.address?.street ); // undefined (no error) -``` - -The code is short and clean, there's no duplication at all. - -Reading the address with `user?.address` works even if `user` object doesn't exist: - -```js run -let user = null; - -alert( user?.address ); // undefined -alert( user?.address.street ); // undefined -``` - -Please note: the `?.` syntax makes optional the value before it, but not any further. - -E.g. in `user?.address.street.name` the `?.` allows `user` to safely be `null/undefined` (and returns `undefined` in that case), but that's only for `user`. Further properties are accessed in a regular way. If we want some of them to be optional, then we'll need to replace more `.` with `?.`. - -```warn header="Don't overuse the optional chaining" -We should use `?.` only where it's ok that something doesn't exist. - -For example, if according to our coding logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`. - -So, if `user` happens to be undefined due to a mistake, we'll see a programming error about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug. -``` - -````warn header="The variable before `?.` must be declared" -If there's no variable `user` at all, then `user?.anything` triggers an error: - -```js run -// ReferenceError: user is not defined -user?.address; -``` -The variable must be declared (e.g. `let/const/var user` or as a function parameter). The optional chaining works only for declared variables. -```` - -## Short-circuiting - -As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist. - -So, if there are any further function calls or side effects, they don't occur. - -For instance: - -```js run -let user = null; -let x = 0; - -user?.sayHi(x++); // no "sayHi", so the execution doesn't reach x++ - -alert(x); // 0, value not incremented -``` - -## Other variants: ?.(), ?.[] - -The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets. - -For example, `?.()` is used to call a function that may not exist. - -In the code below, some of our users have `admin` method, and some don't: - -```js run -let userAdmin = { - admin() { - alert("I am admin"); - } -}; - -let userGuest = {}; - -*!* -userAdmin.admin?.(); // I am admin -*/!* - -*!* -userGuest.admin?.(); // nothing (no such method) -*/!* -``` - -Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the user object exists, so it's safe read from it. - -Then `?.()` checks the left part: if the admin function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors. - -The `?.[]` syntax also works, if we'd like to use brackets `[]` to access properties instead of dot `.`. Similar to previous cases, it allows to safely read a property from an object that may not exist. - -```js run -let key = "firstName"; - -let user1 = { - firstName: "John" -}; - -let user2 = null; - -alert( user1?.[key] ); // John -alert( user2?.[key] ); // undefined -``` - -Also we can use `?.` with `delete`: - -```js run -delete user?.name; // delete user.name if user exists -``` - -````warn header="We can use `?.` for safe reading and deleting, but not writing" -The optional chaining `?.` has no use at the left side of an assignment. - -For example: -```js run -let user = null; - -user?.name = "John"; // Error, doesn't work -// because it evaluates to undefined = "John" -``` - -It's just not that smart. -```` - -## Summary - -The optional chaining `?.` syntax has three forms: - -1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`. -2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `undefined`. -3. `obj.method?.()` -- calls `obj.method()` if `obj.method` exists, otherwise returns `undefined`. - -As we can see, all of them are straightforward and simple to use. The `?.` checks the left part for `null/undefined` and allows the evaluation to proceed if it's not so. - -A chain of `?.` allows to safely access nested properties. - -Still, we should apply `?.` carefully, only where it's acceptable that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. +Optional chaining หรือ `?.` เป็นวิธีที่ปลอดภัยในการเข้าถึงคุณสมบัติแบบซ้อนของออบเจ็กต์ แม้ว่าคุณสมบัติระหว่างทางจะไม่มีอยู่ก็ตาม From 82d9cfd3a5c43af2c6d12d6178bc5ac4c2c47e98 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:04:17 +0700 Subject: [PATCH 2/8] Translate the "Objects: the basics" section to Thai and update optional chaining examples --- .../07-optional-chaining/article.md | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index b6d6395e6..0972cb5c7 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -3,3 +3,28 @@ [recent browser="new"] Optional chaining หรือ `?.` เป็นวิธีที่ปลอดภัยในการเข้าถึงคุณสมบัติแบบซ้อนของออบเจ็กต์ แม้ว่าคุณสมบัติระหว่างทางจะไม่มีอยู่ก็ตาม + +## ปัญหาเมื่อเข้าถึงคุณสมบัติที่ไม่มีอยู่ + +ยกตัวอย่างเช่น สมมติเรามีออบเจ็กต์ `user` ที่เก็บข้อมูลผู้ใช้ โดยผู้ใช้ส่วนใหญ่มีที่อยู่อยู่ใน `user.address` ซึ่งภายในมี `user.address.street` เก็บชื่อถนน แต่ผู้ใช้บางคนอาจไม่ได้ระบุที่อยู่ไว้ + +เมื่อเราพยายามเข้าถึง `user.address.street` โดยที่ผู้ใช้ไม่มีที่อยู่ จะเกิดข้อผิดพลาดแบบนี้: + +```js run +let user = {}; // ผู้ใช้ที่ไม่มีคุณสมบัติ "address" + +alert(user.address.street); // เกิด Error! +``` + +นั่นคือผลลัพธ์ปกติของ JavaScript เพราะ `user.address` เป็น `undefined` การเข้าถึง `user.address.street` จึงล้มเหลว + +ในความเป็นจริง หลายครั้งเราอาจต้องการให้คืนค่า `undefined` กลับมาแทนข้อผิดพลาด (เช่น หมายถึง "ไม่มีถนน") + +อีกตัวอย่างคือเมื่อเรียกใช้ `document.querySelector('.elem')` เพื่อหาองค์ประกอบใน HTML ถ้าไม่เจอจะคืนค่า `null` กลับมา แล้วเมื่อเราพยายามเข้าถึง property ของมัน อย่าง `.innerHTML` ก็จะเกิด error เช่นกัน: + +```js run +// document.querySelector('.elem') จะเป็น null ถ้าไม่เจอ element นั้น +let html = document.querySelector('.elem').innerHTML; // เกิด Error ถ้าเป็น null +``` + +อีกครั้ง ในหลายกรณีที่ไม่เจอ element ก็ถือเป็นเรื่องปกติ เราอาจต้องการให้คืนค่า `html` เป็น `null` แทนที่จะเกิด error \ No newline at end of file From f76c198b6356cabd50fabfe78480750d7a4c7393 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:04:34 +0700 Subject: [PATCH 3/8] Update optional chaining examples and translate the "Objects: the basics" section to Thai --- .../07-optional-chaining/article.md | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 0972cb5c7..cc0f91536 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -27,4 +27,40 @@ alert(user.address.street); // เกิด Error! let html = document.querySelector('.elem').innerHTML; // เกิด Error ถ้าเป็น null ``` -อีกครั้ง ในหลายกรณีที่ไม่เจอ element ก็ถือเป็นเรื่องปกติ เราอาจต้องการให้คืนค่า `html` เป็น `null` แทนที่จะเกิด error \ No newline at end of file +อีกครั้ง ในหลายกรณีที่ไม่เจอ element ก็ถือเป็นเรื่องปกติ เราอาจต้องการให้คืนค่า `html` เป็น `null` แทนที่จะเกิด error + +## วิธีแก้ไขเดิมก่อนมี Optional Chaining + +ก่อนที่จะมี optional chaining `?.` เราต้องเช็คค่าด้วย `if` หรือ `&&` ก่อนที่จะเข้าถึง property ต่อๆ ไป เช่น: + +```js +let user = {}; + +alert(user.address ? user.address.street : undefined); +``` + +หรือในกรณี `document.querySelector`: + +```js run +let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null; +``` + +ใช้ได้ แต่ดูยุ่งเหยิงและต้องเช็คซ้ำๆ โดยเฉพาะกับ property ที่ซ้อนกันหลายชั้น เช่น `user.address.street.name` + +```js +let user = {}; // ผู้ใช้ไม่มีที่อยู่ + +alert(user.address ? user.address.street ? user.address.street.name : null : null); +``` + +อีกวิธีที่ดูดีกว่าเล็กน้อยคือใช้ `&&`: + +```js run +let user = {}; // ผู้ใช้ไม่มีที่อยู่ + +alert( user.address && user.address.street && user.address.street.name ); // undefined (ไม่เกิด error) +``` + +แต่ก็ยังต้องเช็ค property ซ้ำๆ อยู่ดี + +นี่จึงเป็นที่มาของ optional chaining `?.` เพื่อแก้ปัญหานี้ครั้งเดียวจบ! From 372b75542e9e61eeff620d1b71e14e9d21f072fc Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:04:55 +0700 Subject: [PATCH 4/8] Update optional chaining examples and translate the "Objects: the basics" section to Thai --- .../07-optional-chaining/article.md | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index cc0f91536..7483c389d 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -64,3 +64,60 @@ alert( user.address && user.address.street && user.address.street.name ); // und แต่ก็ยังต้องเช็ค property ซ้ำๆ อยู่ดี นี่จึงเป็นที่มาของ optional chaining `?.` เพื่อแก้ปัญหานี้ครั้งเดียวจบ! + +## Optional Chaining กับ Property: `?.` + +Optional chaining `?.` จะหยุดการทำงานทันที ถ้าค่าทางซ้ายของ `?.` เป็น `undefined` หรือ `null` และจะคืนค่า `undefined` กลับมา + +**ในบทความนี้ เพื่อความกระชับ เราจะใช้คำว่า "มีอยู่" หมายถึงไม่เป็น `null` หรือ `undefined`** + +กล่าวคือ `value?.prop`: +- จะทำงานเหมือน `value.prop` ถ้า `value` มีอยู่ +- ถ้า `value` เป็น `undefined/null` จะคืนค่า `undefined` + +ตัวอย่างการใช้ `?.` เพื่อเข้าถึง `user.address.street`: + +```js run +let user = {}; // ผู้ใช้ไม่มีที่อยู่ + +alert( user?.address?.street ); // undefined (ไม่เกิด error) +``` + +โค้ดสั้นลง และไม่มีการเช็คซ้ำๆ + +กับตัวอย่าง `document.querySelector`: + +```js run +let html = document.querySelector('.elem')?.innerHTML; // จะเป็น undefined ถ้าไม่เจอ element +``` + +แม้แต่ในกรณีที่ไม่มีตัวแปร `user` เลย ก็ยังใช้ `?.` ได้อย่างปลอดภัย: + +```js run +let user = null; + +alert( user?.address ); // undefined +alert( user?.address.street ); // undefined +``` + +โปรดสังเกตว่า `?.` ทำให้ส่วนทางซ้ายมันเป็น optional ได้ แต่ไม่ใช่ส่วนถัดไป + +ใน `user?.address.street.name` ตัว `?.` อนุญาตให้ `user` เป็น `null/undefined` แต่ส่วนที่เหลือ (`address`, `street`, `name`) จะถูกเข้าถึงแบบปกติ ถ้าเราอยากให้ส่วนอื่นเป็น optional ด้วย ต้องแทน `.` ด้วย `?.` เพิ่มเติม + +```warn header="ใช้ ?. อย่างพอดี" +เราควรใช้ `?.` เฉพาะในกรณีที่ยอมรับได้หากบางอย่างไม่มีอยู่ + +เช่น ถ้าตามตรรกะของโปรแกรมแล้ว `user` ต้องมีอยู่ แต่ `address` เป็น optional ได้ เราควรเขียน `user.address?.street` แต่ไม่ใช่ `user?.address?.street` + +มิฉะนั้น ถ้าใช้ `?.` มากเกินไป เวลามีข้อผิดพลาดขึ้นมาจริงๆ มันอาจถูกซ่อนเงียบไว้ ทำให้ยากต่อการดีบั๊กในภายหลัง +``` + +````warn header="ตัวแปรทางซ้ายของ ?. ต้องถูกประกาศก่อน" +ถ้าไม่มีตัวแปรนั้นเลย เช่น `user?.anything` จะเกิด error: + +```js run +// ReferenceError: user is not defined +user?.address; +``` +ตัวแปรจะต้องถูกประกาศก่อน จากนั้น optional chaining จึงจะใช้งานได้ +```` \ No newline at end of file From f27c3e7631b6ec90b9eb2e37f7a064b324e28d3c Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:05:12 +0700 Subject: [PATCH 5/8] Update optional chaining examples and translate the "Objects: the basics" section to Thai --- .../07-optional-chaining/article.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 7483c389d..ebbd42b0a 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -120,4 +120,17 @@ alert( user?.address.street ); // undefined user?.address; ``` ตัวแปรจะต้องถูกประกาศก่อน จากนั้น optional chaining จึงจะใช้งานได้ -```` \ No newline at end of file +```` + +## Short-Circuiting + +`?.` จะหยุดการทำงานทันทีถ้าส่วนซ้ายไม่มีอยู่ (เป็น `null/undefined`) ดังนั้นถ้ามีการเรียก function หรือคำสั่งอื่นๆ ทางขวาของ `?.` จะไม่ถูกรันเลย + +```js run +let user = null; +let x = 0; + +user?.sayHi(x++); // ไม่มี "user" จึงไม่ถึงการเรียก sayHi และ x++ + +alert(x); // 0, ค่า x ไม่ถูกเพิ่ม +``` \ No newline at end of file From 962af02aa156e353283199a98e8a793aa08ef991 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:05:29 +0700 Subject: [PATCH 6/8] Update optional chaining examples and translate the "Objects: the basics" section to Thai --- .../07-optional-chaining/article.md | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index ebbd42b0a..72c4cc23b 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -133,4 +133,30 @@ let x = 0; user?.sayHi(x++); // ไม่มี "user" จึงไม่ถึงการเรียก sayHi และ x++ alert(x); // 0, ค่า x ไม่ถูกเพิ่ม -``` \ No newline at end of file +``` + +## Optional Chaining กับ Function: `?.()` + +`?.()` ใช้เพื่อเรียก function ที่อาจจะไม่มีอยู่ + +ตัวอย่างเช่นในโค้ดด้านล่าง ผู้ใช้บางคนมี method `admin` บางคนไม่มี: + +```js run +let userAdmin = { + admin() { + alert("ฉันคือ admin"); + } +}; + +let userGuest = {}; + +*!* +userAdmin.admin?.(); // ฉันคือ admin +*/!* + +*!* +userGuest.admin?.(); // ไม่มีอะไรเกิดขึ้น (ไม่มี method admin) +*/!* +``` + +สังเกตว่าเราใช้ `.` เพื่อเข้าถึง `admin` ก่อน เพราะเรามั่นใจว่าตัวแปร `user` มีอยู่แน่ๆ จากนั้นจึงตามด้วย `?.()` \ No newline at end of file From 99c76d1fd9dd13a6168bb7e0ff8d40c0ff1b626c Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:05:41 +0700 Subject: [PATCH 7/8] Update optional chaining examples and translate the "Objects: the basics" section to Thai --- .../07-optional-chaining/article.md | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 72c4cc23b..6978de14a 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -159,4 +159,37 @@ userGuest.admin?.(); // ไม่มีอะไรเกิดขึ้น (ไ */!* ``` -สังเกตว่าเราใช้ `.` เพื่อเข้าถึง `admin` ก่อน เพราะเรามั่นใจว่าตัวแปร `user` มีอยู่แน่ๆ จากนั้นจึงตามด้วย `?.()` \ No newline at end of file +สังเกตว่าเราใช้ `.` เพื่อเข้าถึง `admin` ก่อน เพราะเรามั่นใจว่าตัวแปร `user` มีอยู่แน่ๆ จากนั้นจึงตามด้วย `?.()` + +## Optional Chaining กับ [] : `?.[]` + +ถ้าเราต้องการใช้ `[]` เพื่อเข้าถึง property แทนที่จะใช้ `.` ก็ใช้ `?.[]` ได้ + +```js run +let key = "firstName"; + +let user1 = { + firstName: "John" +}; + +let user2 = null; + +alert( user1?.[key] ); // John +alert( user2?.[key] ); // undefined +``` + +และสามารถใช้กับ `delete` ได้ด้วย: + +```js run +delete user?.name; // ลบ user.name ถ้า user มีอยู่ +``` + +````warn header="ใช้ ?. ได้แค่อ่านและลบ ไม่ใช่การเขียน" +Optional chaining `?.` ไม่ใช้ในด้านซ้ายของการกำหนดค่า + +```js run +let user = null; + +user?.name = "John"; // Error เพราะจะประเมินเป็น undefined = "John" +``` +```` \ No newline at end of file From 64b66996a82eabca00bf3da33c6712a33e7f22e8 Mon Sep 17 00:00:00 2001 From: Prasit Tongpradit Date: Tue, 16 Apr 2024 00:05:49 +0700 Subject: [PATCH 8/8] Update optional chaining examples and translate the "Objects: the basics" section to Thai --- .../07-optional-chaining/article.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 6978de14a..01cd14cb6 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -192,4 +192,18 @@ let user = null; user?.name = "John"; // Error เพราะจะประเมินเป็น undefined = "John" ``` -```` \ No newline at end of file +```` + +## สรุป + +ไวยากรณ์ Optional chaining `?.` มี 3 รูปแบบ: + +1. `obj?.prop` -- คืนค่า `obj.prop` ถ้า `obj` มีอยู่ ไม่งั้นคืน `undefined` +2. `obj?.[prop]` -- คืนค่า `obj[prop]` ถ้า `obj` มีอยู่ ไม่งั้นคืน `undefined` +3. `obj.method?.()` -- เรียก `obj.method()` ถ้า `obj.method` มีอยู่ ไม่งั้นคืน `undefined` + +`?.` จะเช็ค `null/undefined` ทางด้านซ้าย และอนุญาตให้เข้าถึงต่อไปได้ถ้าไม่ใช่ + +การเรียงต่อกันหลายตัวของ `?.` ทำให้เข้าถึง property ที่ซ้อนกันได้อย่างปลอดภัย + +อย่างไรก็ตาม ควรใช้ `?.` อย่างระมัดระวัง เฉพาะในกรณีที่ยอมรับได้หากบางอย่างไม่มีอยู่จริง เพื่อไม่ให้ข้อผิดพลาดที่ควรเกิดถูกซ่อนเงียบไป \ No newline at end of file