به سه عملگر ||
و &&
و !
در جاوااسکریپت عملگرهای منطقی میگوییم.
عملگر ||
به معنی «یا» است (OR).
عملگر &&
به معنی «و» است (AND).
عملگر !
نیز به صورت NOT خوانده میشود.
این عملگرها فقط منحصر به مقادیر بولین نیست، این عملگرها روی هر نوع دیتاتایپی قابل اعمال است و خروجی هم از هر نوع دیتاتایپی ممکن است باشد.
در ادامه بیشتر در مورد آنها بحث میکنیم.
عملگر ||
«یا»
سینتکس عملگر ||
به این صورت است:
result = a || b;
عملگر «||
» در خیلی از زبانهای برنامهنویسی به مقادیر بولین اختصاص دارد. معنی آن نیز این است که آیا طرف راست یا طرف چپ true است؟ اگر هر یک از طرفین true باشد، خروجی آن true خواهد شد، وگرنه false میشود.
البته کار این عملگر در جاوااسکریپت فراتر از اینهاست. ولی برای این که گیج نشویم بگذارید تا اینجا با همان مقادیر بولین چند مثال ببینیم.
تمام ترکیبات مختلف بولین را تست میکنیم:
alert( true || true ); // true
alert( false || true ); // true
alert( true || false ); // true
alert( false || false ); // false
همان طور که میبینید خروجی این عملگر همیشه میشود true
، مگر اینکه هر دو طرف false
باشد.
اگر یکی از طرفین بولین نباشد، برای اینکه بتوان خروجی نهایی را پیدا کرد به بولین تبدیل میشود.
مثلاً با عدد ۱
مثل true
رفتار میشود و با عدد ۰
مثل false
:
if (1 || 0) { // انگار نوشتهایم (true || false)
alert( 'درسته!' );
}
از عملگر OR معمولاً درون if
استفاده میکنیم، تا بررسی کنیم که آیا یکی از طرفین true
هست یا نه.
مثال:
let hour = 9;
if (hour < 10 || hour > 18) {
alert( 'شرکت بسته است.' );
}
میتوانیم شرطهای دیگری نیز اضافه کنیم:
let hour = 12;
let isWeekend = true;
if (hour < 10 || hour > 18 || isWeekend) {
alert( 'شرکت بسته است.' ); // چون آخرهفته است
}
عملگر ||
اوّلین مقدار truthy را پیدا میکند
به مقداری که در تبدیل به بولین معادل true است truthy میگوییم، مثلاً رشتهی "test"
یا عدد ۵
مقدارهایی truthy هستند، ولی عدد ۰
یا رشتهی ""
مقدارهایی truthy نیستند.
اگر مقداری truthy نبود، به آن falsy میگوییم.
چیزی که تا به حال در مورد عملگر ||
یاد گرفتیم، همان قابلیتهای معمولی آن است که در سایر زبانها نیز دیده میشود. ولی عملگر ||
در جاوااسکریپت دارای قابلیتهای اضافهتری است.
به صورت کلی عملگر || در جاوااسکریپت به این صورت عمل میکند:
در ابتدا چند مقدار را در نظر بگیرید که بینشان عملگر ||
قرار دارد:
result = value1 || value2 || value3;
عملگر ||
به این شکل کار میکند:
- عملوندها را از چپ به راست بررسی میکند.
- هر عملوند را به بولین تبدیل میکند. اگر نتیجه
true
بشود، کار را ادامه نمیدهد و همین مقدار را به عنوان نتیجه بر میگرداند. - اگر تمام عملوندها بررسی بشوند (مثلاُ در حالتی که همه
false
باشند)، آخرین عملوند را به عنوان نتیجه بر میگرداند.
نکتهی مهم این است که نتیجه، همان مقدار اصلی عملوند است، قبل از تبدیل به بولین!
به عبارت دیگر، زنجیرهای از ||
ها اوّلین مقدار truthy را بر میگرداند، و در صورت عدم وجود مقدار truthy، آخرین مقدار را بر میگرداند.
مثال:
alert( 1 || 0 ); // 1 (1 is truthy)
alert( true || 'اصلاً مهم نیست اینجا چیست' ); // (true is truthy)
alert( null || 1 ); // 1 (1 is the first truthy)
alert( null || 0 || 1 ); // 1 (first truthy)
// در مثال زیر هیچکدام truthy نیست، در نتیجه آخرین مقدار موجود بر میگردد
alert( undefined || null || 0 ); // 0
این قابلیت عملگر ||
به ما امکان میدهد کارهایی بکنیم که در زبانهای برنامهنویسی دیگر نمیتوانستیم بکنیم.
۱. گرفتن اوّلین truthy در لیستی از مقدارها
فرض کنید لیستی از متغیّرها دارید که ممکن است مقدارشان null
یا undefined
باشد، یا اینکه دادهی معتبری درونشان باشد. با این وضعیّت چگونه میتوانیم مقدار اوّلین متغیّری که دارای مقدار بود را به دست آوریم؟
میتوانیم از عملگر ||
استفاده کنیم:
let currentUser = null;
let defaultUser = "علی";
let name = currentUser || defaultUser || "گمنام";
// در مثال زیر «علی» انتخاب میشود، زیرا که اوّلین truthy است
alert( name );
اگر در مثال بالا currentUser
و defaultUser
هر دو falsy بودند، نتیجه میشد "گمنام"
.
۲. اتّصال کوتاه
در دو طرف ||
ممکن است هر عبارت دلخواهی وجود داشته باشد. عملگر ||
این عبارتها را از چپ به راست اجرا میکند و بعد مقدارشان را بررسی میکند و به محض رسیدن به اوّلین truthy متوقّف میشود و عبارتهای بعدی را کلاً اجرا و بررسی نمیکند. به این فرآیند «اتّصال کوتاه» میگوییم.
اگر سمت راستِ ||
عبارتی باشد که اثر جانبی داشته باشد به وضوح این رفتار دیده خواهد شد. در مثال زیر، متغیّر x
مقداری نمیگیرد:
let x;
true || (x = 1);
alert(x); // undefined, اصلا اجرا نشده است (x = 1) زیرا
حالا اگر در اینجا عملوند سمت چپ false
بود، عملگر ||
سمت راست خود را نیز اجرا و بررسی میکند، لذا عمل انتساب انجام خواهد شد:
let x;
false || (x = 1);
alert(x); // 1
همان طور که میبینید، میتوان گفت این طرز استفاده از ||
، همان کار if
را انجام میدهد. عملوند سمت چپ به بولین تبدیل میشود، اگر true
بود سمت راست اجرا میشود.
البته معمولاً استفاده از همان if معمولی، کد را خواناتر میکند. ولی گاهی اوقات این روش هم بد نیست.
عملگر && «وَ»
سینتکس:
result = a && b;
این عملگر در خیلی از زبانهای برنامهنویسی فقط مربوط به بولینهاست، و تنها در صورتی مقدار true
را بر میگرداند که هر دو طرف truthy باشد، در غیر این صورت false
را بر میگرداند:
alert( true && true ); // true
alert( false && true ); // false
alert( true && false ); // false
alert( false && false ); // false
از این عملگر معمولاً درون if
استفاده میکنیم:
let hour = 12;
let minute = 30;
// اگر ساعت مساوی ۱۲ بود وَ دقیقه هم مساوی ۳۰ بود
if (hour == 12 && minute == 30) {
alert( 'time is 12:30' );
}
درست مثل عملگر ||
در اینجا هم هر مقداری را میتوان به عنوان عملوند &&
استفاده کرد.
if (1 && 0) { // انگار نوشتهایم true && false
alert( "اجرا نمیشود، چون نتیجه false است." );
}
عملگر &&
اوّلین مقدار falsy را پیدا میکند
چند مقدار را که بینشان عملگر &&
قرار داشته باشد در نظر بگیرید:
result = value1 && value2 && value3;
عملگر &&
به این صورت کار میکند:
- ابتدا عملوندها را از چپ به راست اجرا و بررسی میکند.
- هر عملوند را به بولین تبدیل میکند. اگر نتیجه false شد، کار را متوقّف کرده و مقدار اصلی عملوند را به عنوان نتیجه بر میگرداند.
- اگر همهٔ عملوندها اجرا و بررسی شدند (مثلاً در حالتی که همهٔ مقادیر truthy هستند)، آخرین عملوند را بر میگرداند.
بهعبارتِدیگر عملگر &&
اوّلین مقدار falsy را بر میگرداند، و در صورت عدم وجود مقدار falsy، آخرین مقدار موجود را بر میگرداند.
قواعدی که قبلاً در مورد OR گفتیم دربارهی &&
هم صدق میکند، ولی با این تفاوت که &&
اوّلین falsy را بر میگرداند درحالیکه ||
اوّلین truthy را بر میگرداند.
مثال:
// اگر اولین عملوند truthy باشد
// این عملگر دومی را بر میگرداند
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// اگر عملوند اوّل falsy باشد
// عملگر «و» همان را بر میگرداند و دومی را کلا نادیده میگیرد
alert( null && 5 ); // null
alert( 0 && "اصلاً مهم نیست اینجا چیست" ); // ۰
اگر بیشتر از دو مقدار پشت سر هم بنویسید، باز هم اوّلین falsy بر میگردد:
alert( 1 && 2 && null && 3 ); // null
اگر همهی مقدارها truthy باشند، آخرین مقدار موجود بر میگردد:
alert( 1 && 2 && 3 ); // 3, آخرین مقدار
اولویت &&
بیشتر از ||
است
اولویت && بیشتر از || است. بنابراین عبارت a && b || c && d
دقیقاً معادل عبارت (a && b) || (c && d)
است
درست مثل ||
، عملگر &&
هم میتواند جایگزین if
شود.
مثال:
let x = 1;
(x > 0) && alert( 'ایکس از صفر بزرگتر است!' );
دستوری که سمت راست &&
نوشته شده است تنها در صورتی اجرا میشود که به آن برسیم، و این در حالتی است که (x > 0)
معادل true
باشد.
لذا کد بالا دقیقاً مشابه کد زیر عمل میکند:
let x = 1;
if (x > 0) {
alert( 'ایکس از صفر بزرگتر است!' );
}
اگرچه در حالت اوّل که در آن از &&
استفاده کردیم کد کمتری نوشتهایم، ولی حالت دوم که با if
نوشته شده است بهتر و خواناتر است.
توصیهی ما این است که از هر چیزی سر جایش استفاده کنید. اگر میخواهید شرطی را بررسی کنید از if
استفاده کنید، و اگر میخواهید درستی چند شرط با هم را بررسی کنید از &&
استفاده کنید.
عملگرِ !
عملگر NOT به صورت علامت تعجّب نوشته میشود.
سینتکس آن به این صورت است:
result = !value;
عملگر NOT تنها یک عملوند میپذیرد و به این صورت عمل میکند:
- عملوند را به بولین تبدیل میکند که در نهایت میشود
true
یاfalse
. - سپس برعکس آن را بر میگرداند. یعنی اگر
true
بودfalse
را برمیگرداند و اگرfalse
بودtrue
را بر میگرداند.
مثال:
alert( !true ); // false
alert( !0 ); // true
میتوانید از دوتا NOT پشت سر هم (!!
) برای تبدیل دیتاتایپ به بولین استفاده کنید:
alert( !!"non-empty string" ); // true
alert( !!null ); // false
در این حالت NOT اوّل، مقدار را به بولین تبدیل میکند و برعکس آن را بر میگرداند، سپس NOT دوم دوباره آن را برعکس میکند. در نهایت همان مقدار اوّلیه را داریم که به بولین تبدیل شده است.
این دقیقاً همان کار تابع Boolean را انجام میدهد:
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
اولویّت عملگر NOT از تمام عملگرهای منطقی دیگر بیشتر است.