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 c4a042130..e3850c6cb 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -1,17 +1,17 @@ +# Optional chaining '?.' یا زنجیره ای اختیاری +[recent browser="new"] -# Optional chaining '?.' +###### زنجیره ای اختیاری روشی بدون خطا برای دستیابی به ویژگی های(properties) داخلی شی است حتی در زمانی که ویژگی میانی وجود نداشته باشد -[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. +برای مثال, بیاید یک شی(object) برای اطلاعات کاربران در نظر بگیریم. تعدادی از کاربران ما آدرس را در ویژگی `user.address` و خیابان را در ویژگی `user.address.street` دارند ولی تعدادی کمی از آن ها آدرس را ارائه نکرده‌اند. -As an example, let's consider objects for user data. Most of our users have addresses in `user.address` property, with the street `user.address.street`, but some did not provide them. +در این صورت تلاش ما برای دستیابی به `user.address.street` با شکست مواجه خواهد شد -In such case, when we attempt to get `user.address.street`, we'll get an error: ```js run let user = {}; // the user without "address" property @@ -19,18 +19,22 @@ let user = {}; // the user without "address" property alert(user.address.street); // Error! ``` -That's the expected result, JavaScript works like this, but many practical cases we'd prefer to get `undefined` instead of an error (meaning "no street"). +این یک خروجی قابل حدس است٬ جاوااسکریپت اینگونه کار میکند٬ ولی در مثال های عملی ترجیح میدهیم ‍``undefined`` دریافت کنیم به جای خطا. + +یا مثالی دیگر در توسعه وب٬ ما میخواهیم اطلاعاتی در مورد اِلمانی در صفحه را بگیریم٬ که ممکن بعضی اوقات وجود نداشته باشد : + -...And another example. In the web development, we may need to get an information about an element on the page, that sometimes doesn't exist: + +یا در توسعه وب٬ ما میخواهیم اطلاعاتی در مورد اِلمان در صفحه را بگیریم٬ ولی شاید وجود نداشته باشد : ```js run // Error if the result of querySelector(...) is null let html = document.querySelector('.my-element').innerHTML; ``` -Before `?.` appeared in the language, the `&&` operator was used to work around that. -For example: + +قبل از اینکه `?.` در زبان وجود داشته باشد از عمگر `&&` برای کار در این مورد استفاده میشد. برای مثال : ```js run let user = {}; // user has no address @@ -38,15 +42,18 @@ let user = {}; // user has no address alert( user && user.address && user.address.street ); // undefined (no error) ``` -AND'ing the whole path to the property ensures that all components exist (if not, the evaluation stops), but is cumbersome to write. +AND کردن کل مسیر رسیدن به ویژگی ، وجود همه اجزا را تضمین می کند(اگر ارزیابی متوقف نشود) ، اما نوشتن آن دست و پا گیر است. + + +## زنجیره ای اختیاری -## Optional chaining +زنجیره ای اختیاری `?.` ارزیابی را متوقف میکند اگر مقدار قبل از قسمت `?.` برابر با `undefined` یا `null` باشد و مقدار `undefined` را برمیگرداند. -The optional chaining `?.` stops the evaluation and returns `undefined` if the part before `?.` is `undefined` or `null`. +**در ادامه این مقاله ، به اختصار خواهیم گفت چیزی وجود خواهد داشت اگر که `undefined` و `null` نباشد.** -**Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`.** -Here's the safe way to access `user.address.street`: + +این یک مسیر امن برای دستیابی `user.address.street` است : ```js run let user = {}; // user has no address @@ -54,7 +61,9 @@ let user = {}; // user has no address alert( user?.address?.street ); // undefined (no error) ``` -Reading the address with `user?.address` works even if `user` object doesn't exist: + + +خواندن آدرس با `user?.address` کار خواهد کرد حتی زمانی هم که شی `user` وجود ندارد : ```js run let user = null; @@ -63,39 +72,45 @@ alert( user?.address ); // undefined alert( user?.address.street ); // undefined ``` -Please note: the `?.` syntax makes optional the value before it, but not any further. +لطفا توجه داشته باشید : سینتکس `?.` مقدارهای قبلی را اختیاری میکند نه مقدارهای جلوی آن را. + +در مثال بالا `user?.` به `user` مقدار `null/undefined` خواهد داد. -In the example above, `user?.` allows only `user` to be `null/undefined`. -On the other hand, if `user` does exist, then it must have `user.address` property, otherwise `user?.address.street` gives an error at the second dot. -```warn header="Don't overuse the optional chaining" -We should use `?.` only where it's ok that something doesn't exist. +از طرف دیگر ، اگر ‍‍`user` وجود داشته باشد ، پس باید ویژگی `user.address` داشته باشد ، در غیر این صورت `user؟.address.street `در نقطه دوم خطا می دهد. -For example, if according to our coding logic `user` object must be there, but `address` is optional, then `user.address?.street` would be better. +```warn header="از زنجیر اختیاری بیش از حد استفاده تکنید" -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. +ما باید از `?.` فقط زمانی استفاده کنیم که عدم وجود چیزی اشکالی ندارد + +به عنوان مثال ، اگر مطابق منطق برنامه نویسی ما ، شی `user` باید وجود داشته باشد ولی `address` اختیاری است در آن شرایط استفاده از `user.address?.street` راه حل بهتری است ، + +بنابراین ، اگر تصادفاً به دلیل اشتباهی ‍`user` برابر با `undefined` باشد، شاهد یک خطای برنامه نویسی در مورد آن خواهیم بود و آن را برطرف خواهیم کرد. در غیر این صورت ، خطاهای کد را می توان در مواردی که مناسب نیست ساکت کرد٬ و کار اشکال زدایی را سخت تر میکند. ``` -````warn header="The variable before `?.` must be declared" -If there's no variable `user` at all, then `user?.anything` triggers an error: + + +````warn header="متغیر قبل از ؟. باید تعریف شده باشد" اگر متغیر user به هیچ وجه وجود نداشته باشد `user?.anything` خطا خواهد داد + + ```js run // ReferenceError: user is not defined user?.address; ``` -There must be a declaration (e.g. `let/const/var user`). The optional chaining works only for declared variables. -```` - -## Short-circuiting +باید تعریفی باشد( `let/const/var user ` ). زنجیره ای اختیاری فقط برای متغیرهای تعریف شده کار می کند. +باید `let/const/var user ` وجود داشته باشد. زنجیره ای اختیاری فقط برای متغیرهای تعریف شده کار می کند. -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 +​```js run let user = null; let x = 0; @@ -104,13 +119,15 @@ 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: +در کد زیر٬ برخی از کاربران ما متد `admin` را دارند و برخی خیر : ```js run let user1 = { @@ -127,11 +144,11 @@ user2.admin?.(); */!* ``` -Here, in both lines we first use the dot (`user1.admin`) to get `admin` property, because the user object must exist, so it's safe read from it. +در اینجا در هر دو خط ما ابتدا از `.` (`user1.admin`) برای گرفتن ویژگی ‍`admin` استفاده میکنیم به خاطر اینکه شی ‍`user` حتما وجود دارد پس برای خواندن از آن مطمئن هستیم. -Then `?.()` checks the left part: if the admin function exists, then it runs (that's so for `user1`). Otherwise (for `user2`) the evaluation stops without errors. +سپس `?.()` عبارت سمت چپ را بررسی میکند: اگر تابع ‍`admin` وجود داشته باشد آنرا اجرا میکند(برای ‍`user1`) در غیر اینصورت(برای `user2`) محاسبات بدون خطا به متوقف میشود. -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 user1 = { @@ -148,16 +165,19 @@ alert( user2?.[key] ); // undefined alert( user1?.[key]?.something?.not?.existing); // undefined ``` -Also we can use `?.` with `delete`: + + +همچنان ما میتوانیم از `?.` در `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. +````warn header="ما میتوانیم از`؟.` برای پاک کردن و خواندن مطمئن استفاده کنیم ولی نوشتن نه." +زنجیره اختیاری `?.` هیچ کاربردی برای سمت چپ مساوی ندارد. -For example: + +برای مثال: ```js run let user = null; @@ -165,19 +185,23 @@ user?.name = "John"; // Error, doesn't work // because it evaluates to undefined = "John" ``` -It's just not that smart. -```` +آنقدرها هم هوشمند نیست. + + + +## خلاصه + +سینتکس `?.` سه شکل دارد: -## Summary +1. `obj?.prop` - مقدار ‍‍`obj.prop` را برمیگرداند اگر `obj` وجود داشته باشد در غیر اینصورت مقدار `undefined` را برمیگرداند +2. `[obj?.[prop` - مقدار ‍‍`[obj.[prop` را برمیگرداند اگر `obj` وجود داشته باشد در غیر اینصورت مقدار `undefined` را برمیگرداند +3. `()obj.method()` - ‍‍``obj?.method`` را صدا میزند اگر `obj` وجود داشته باشد در غیر اینصورت مقدار `undefined` را برمیگرداند -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`. +همانطور که می بینیم ، همه آنها ساده و آسان برای استفاده هستند. `?.` سمت چپ را از نظر `null/undefined` بررسی می کند و اجازه می دهد تا ارزیابی ادامه یابد اگر برابر با `null/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 to exist. So that it won't hide programming errors from us, if they occur. +با این حال خطاهای برنامه نویسی را از ما مخفی نمیکند اگر آنها اتفاق بیافتند. \ No newline at end of file