۱۳ ژوئیه ۲۰۲۳

عملگر های منطقی

چهار عملگر منطقی در جاوااسکریپت وجود دارد: || (OR)، && (AND)، ! (NOT)، ?? (Nullish Coalescing). اینجا ما سه تای اول را پوشش می دهیم، عملگر ?? در مقاله بعدی است.

با اینکه آنها “منطقی” نام برده می شوند، می توانند روی هر نوع مقداری اعمال شوند، نه فقط نوع بولین. نتیجه آنها هم می تواند از هر نوعی باشد.

بیایید جزییات را ببینیم.

|| (OR)

عملگر “OR(یا)” با نماد دو خط عمودی نمایش داده می شود:

result = a || b;

در برنامه نویسی کلاسیک، عملگر منطقی OR تنها با مقدار های بولین کار می کرد. اگر هر کدام از آرگومان های آن true باشد، ture بر می گرداند، در غیر این صورت false بر می گرداند.

در جاوااسکریپت، این عملگر مقداری فوت و فن و قدرت بیشتری دارد. اما اول، بیایید ببینیم با مقدار های بولین چه اتفاقی می افتد.

چهار ترکیب احتمالی منطقی وجود دارد:

alert( true || true );   // true
alert( false || true );  // true
alert( true || false );  // true
alert( false || false ); // false

همانطور که می بینیم، نتیجه همیشه true است به جز موقعی که هر دو عملوند false باشند.

اگر یک عملوند بولین نباشد، برای ارزیابی به بولین تبدیل می شود.

برای مثال، با عدد 1 مانند true رفتار می شود، با عدد 0 مانند false:

if (1 || 0) { // همانند if( true || false ) کار میکند
  alert( 'truthy!' );
}

اکثر اوقات، 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( 'اداره بسته است.' ); // آخر هفته است
}

OR "||" اولین مقدار truthy را پیدا می کند

منطقی که بالا توصیف شد تا حدی کلاسیک است. الان، بیایید وارد ویژگی های “اضافه” جاوااسکریپت شویم.

الگوریتم توسعه‌ یافته به صورت زیر عمل می کند.

چند مقدار همراه با OR وارد می کنیم:

result = value1 || value2 || value3;

عملگر OR || مراحل پایین را انجام می دهد:

  • عملوند ها را از چپ به راست ارزیابی می کند.
  • هر عملوند را، تبدیل به بولین می کند. اگر نتیجه true باشد، متوقف می شود و مقدار اصلی عملوند را بر می گرداند.
  • اگر تمام عملوند ها ارزیابی شدند (یعنی تمام آنها false بودند)، عملوند آخر را بر می گرداند.

هر مقدار با شکل اصلی خود و بدون تبدیل بر گردانده می شود.

به عبارتی دیگر، یک زنجیره از OR || اولین مقدار truthy یا در صورتی که هیج مقدار truthy پیدا نشود آخرین مقدار را بر می گرداند.

برای مثال:

alert( 1 || 0 ); // 1 (1 is truthy)

alert( null || 1 ); // 1 (1 is the first truthy value)
alert( null || 0 || 1 ); // 1 (the first truthy value)

alert( undefined || null || 0 ); // 0 (all falsy, returns the last value)

این باعث چند استفاده جالب نسبت به “OR خالص، کلاسیک، فقط-بولین” می شود.

  1. گرفتن اولین مقدار truthy از یک لیست متغیر ها یا عبارت ها.

    برای مثال، ما متغیر های firstName، lastName و nickName داریم، همه آنها اختیاری هستند (یعنی می توانند undefined یا مقدارهای falsy داشته باشند).

    بیایید با استفاده از OR || متغیری که دارای داده است را انتخاب کنیم و آن را نمایش دهیم (یا اگر چیزی تنظیم نشده باشد "Anonymous" را):

    let firstName = "";
    let lastName = "";
    let nickName = "SuperCoder";
    
    alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder

    اگر تمام متغیر ها falsy بودند، "Anonymous" نمایش داده می شد.

  2. ارزیابی گردش کوتاه.

    یکی دیگر از ویژگی های اپراتور OR || به اصطلاح ارزیابی “گردش کوتاه” است.

    یعنی اینکه || روی آرگومان های خودش پردازش انجام می دهد تا زمانی که به اولین مقدار truthy برسد، و سپس آن مقدار بلافاصله بر گردانده می شود، بدون اینکه به بقیه آرگومان ها کاری داشته باشد.

    اهمیت این ویژگی زمانی آشکار می شود که یک عملوند فقط یک مقدار ساده نباشد، بلکه یک عبارت با یک اثر جانبی باشد، مثل تخصیص متغیر یا صدا زدن تابع.

    در مثال پایین، فقط پیام دوم چاپ می شود:

    true || alert("چاپ نمی شود");
    false || alert("چاپ می شود");

    در خط اول، عملگر OR || به محض دیدن true ارزیابی را بلافاصله متوقف می کند، پس alert اجرا نمی شود.

    بعضی اوقات، افراد از این ویژگی استفاده می کنند تا دستوراتی را فقط اگر شرط سمت چپ falsy باشد اجرا کنند.

&& (AND)

عملگر AND(و) با دو ampersand && نمایش داده می شود:

result = a && b;

در برنامه نویسی کلاسیک، AND اگر هر دو عملوند truthy باشند true را بر می گرداند و در غیر این صورت 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( 'ساعت 12:30 است' );
}

درست مثل OR، هر مقداری به عنوان عملوند AND مجاز است:

if (1 && 0) { // evaluated as true && false
  alert( "won't work, because the result is falsy" );
}

AND “&&” اولین مقدار falsy را پیدا می کند

چند مقدار را همراه AND می دهیم:

result = value1 && value2 && value3;

عملگر AND && مراحل زیر را انجام می دهد:

  • عملوند ها را از چپ به راست ارزیابی می کند.
  • هر عملوند را به بولین تبدیل می کند. اگر نتیجه false باشد، متوقف می شود و مقدار اصلی آن عملوند را بر می گرداند.
  • اگر تمام عملوند ها ارزیابی شدند (یعنی همه truthy بودند)، آخرین عملوند را بر می گرداند.

به عبارتی دیگر، AND اولین مقدار falsy یا اگر هیچ falsy پیدا نشد آخرین مقدار را بر می گرداند.

قوانین بالا شبیه به قوانین OR هستند. تقاوت این است که AND اولین مقدار falsy را بر می گرداند در حالی که OR اولین مقدار truthy را بر می گرداند.

مثال ها:

// if the first operand is truthy,
// AND returns the second operand:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5

// if the first operand is falsy,
// AND returns it. The second operand is ignored
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0

ما همچنین می توانیم چند مقدار را در یک ردیف قرار بدهیم. ببینید چگونه اولین مقدار falsy بر گردانده می شود.

alert( 1 && 2 && null && 3 ); // null

وقتی که تمام مقدارها truthy باشند، آخرین مقدار بر گردانده می شود:

alert( 1 && 2 && 3 ); // 3, آخرین مقدار
اولویت AND && از OR || بیشتر است

اولویت عملگر AND && بالاتر از OR || است.

بنابراین کد a && b || c && d اساسا مانند این است که عبارت && داخل پرانتر باشد: (a && b) || (c && d).

if را با || یا && جابجا نکنید

بعضی اوقات، افراد از عملگر AND && به عنوان “راه کوتاه تر برای نوشتن if” استفاده می کنند.

برای مثال:

let x = 1;

(x > 0) && alert( 'بزرگ تر از صفر!' );

عمل سمت راست && فقط اگر ارزیابی به آن برسد اجرا می شود. یعنی اینکه، فقط اگر (x > 0) درست باشد.

پس ما اساسا یک شباهت برای کد زیر داریم:

let x = 1;

if (x > 0) alert( 'بزرگ تر از صفر!' );

با اینکه نوعی که همراه با && است ظاهر کوتاه تری دارد، if واضح تر است و کمی خواناتر است. پس ما پیشنهاد ما این است که هر ساختار را برای هدف خودش استفاده کنیم: از if در صورتی که if می خواهیم استفاده کنیم و از && در صورتی که AND می خواهیم استفاده کنیم.

! (NOT)

عملگر NOT(نفی) با یک علامت تعجب ! نمایش داده می شود.

سینتکس بسیار ساده است:

result = !value;

عملگر یک آرگومان قبول می کند و مراحل زیر را انجام می دهد:

  1. عملوند را به نوع بولین تبدیل می کند: true/false.
  2. مقدار معکوس را بر می گرداند.

برای مثال:

alert( !true ); // false
alert( !0 ); // true

بعضی اوقات NOT دوگانه !! برای تبدیل یک مقدار به نوع بولین استفاده می شود:

alert( !!"string که خالی نیست" ); // true
alert( !!null ); // false

یعنی اینکه، اولین NOT مقدار را به بولین تبدیل می کند و معکوس آن را بر می گرداند، و دومین NOT دوباره آن را معکوس می کند. سرانجام، ما یک تبدیل ساده مقدار به بولین خواهیم داشت.

یک راه کلامی تر برای انجام کار مشابه وجود دارد – تابع درون ساخت بولین:

alert( Boolean("string که خالی نیست") ); // true
alert( Boolean(null) ); // false

عملگر NOT ! بالاترین اولویت را بین عملگر های منطقی دارد، بنابراین همیشه اول اجرا می شود، قبل از && یا ||.

تمارین

اهمیت: 5

کد پایین چه چیزی را خروجی خواهد داد؟

alert( null || 2 || undefined );

جواب 2 است، آن اولین مقدار truthy است.

alert( null || 2 || undefined );
اهمیت: 3

کد پایین چه چیزی را خروجی خواهد داد؟

alert( alert(1) || 2 || alert(3) );

جواب: اول 1، سپس 2.

alert( alert(1) || 2 || alert(3) );

صدا زدن alert مقداری بر نمی گرداند. یا، به عبارتی دیگر، undefined را بر می گرداند.

  1. اولین OR || عملوند سمت چپ خود alert(1) را ارزیابی میکند. آن اولین پیام که 1 است را نمایش می دهد.
  2. alert مقدار undefined را بر می گرداند، پس OR به سمت عملوند دوم برای پیدا کردن یک مقدار truthy ادامه می دهد.
  3. عملوند دوم 2 turthy است، پس عملیات متوقف شده، 2 بر گردانده می شود و سپس توسط alert بیرونی نمایش داده می شود.

هیچ 3ای در کار نخواهد بود، چون ارزیابی به alert(3) نمی رسد.

اهمیت: 5

این کد چه چیزی را نمایش خواهد داد؟

alert( 1 && null && 2 );

جواب: null، چون اولین مقدار falsy از لیست است.

alert(1 && null && 2);
اهمیت: 3

این کد چه چیزی را نمایش خواهد داد؟

alert( alert(1) && alert(2) );

جواب: 1، و سپس undefined.

alert( alert(1) && alert(2) );

صدا زدن undefined alert را بر می گرداند (آن فقط یک پیام را نمایش می دهد، پس هیچ return معناداری وجود ندارد).

به خاطر آن، && عملوند چپ را ارزیابی میکند (1 را نمایش می دهد)، و بلافاصله متوقف می شود، چون undefined یک مقدار falsy است. و && به دنبال یک مقدار falsy می گردد و آن را بر می گرداند، بنابراین کار تمام می شود.

اهمیت: 5

نتیجه چه خواهد بود؟

alert( null || 2 && 3 || 4 );

جواب: 3.

alert( null || 2 && 3 || 4 );

اولویت AND && از || بیشتر است، ینابراین اول اجرا می شود.

نتیجه 3 = 3 && 2، پس عبارت تبدیل می شود به:

null || 3 || 4

حالا نتیجه اولین مقدار truthy است: 3.

اهمیت: 3

یک شرط if بنویسید که بررسی کند age بین 14 و 90 به صورتی که شامل خودشان هم بشود هست یا نه.

“شامل خودشان” یعنی age می تواند به مرز 14 و 90 هم برسد.

if (age >= 14 && age <= 90)
اهمیت: 3

یک شرط if بنویسید که بررسی کند age بین 14 و 90 به صورتی که که شامل خود آنها هم بشود نباشد.

دو نوع بسازید: اولی با استفاده از NOT !، و دومی بدون آن.

نوع اول:

if (!(age >= 14 && age <= 90))

نوع دوم:

if (age < 14 || age > 90)
اهمیت: 5

کدام یک از alertها اجرا خواهد شد؟

نتیجه عبارت های داخل (...)if چه خواهد بود؟

if (-1 || 0) alert( 'first' );
if (-1 && 0) alert( 'second' );
if (null || -1 && 1) alert( 'third' );

جواب: اولی و سومی اجرا خواهند شد.

جزییات:

// Runs.
// The result of -1 || 0 = -1, truthy
if (-1 || 0) alert( 'first' );

// Doesn't run
// -1 && 0 = 0, falsy
if (-1 && 0) alert( 'second' );

// Executes
// Operator && has a higher precedence than ||
// so -1 && 1 executes first, giving us the chain:
// null || -1 && 1  ->  null || 1  ->  1
if (null || -1 && 1) alert( 'third' );
اهمیت: 3

کدی بنویسید که با prompt برای login درخواست کند.

اگر بازدید کننده "Admin" وارد کند، سپس برای رمز عبور prompt کنید، اگر ورودی یک خط خالی یا Esc باشد – “Canceled” را نمایش دهید، اگر رشته(string) دیگری باشد – سپس “I don’t know you” را نشان دهید.

رمز عبور به شکل زیر بررسی می شود:

  • اگر برابر با “TheMaster” باشد، سپس “Welcome!” را نمایش دهید،
  • اگر رشته(string) دیگری باشد – “Wrong password” را نمایش دهید،
  • اگر یک رشته(string) خالی یا ورودی cancelled باشد، “Canceled” را نمایش دهید

طرح:

لطفا از بلوک های if تو در تو استفاده کنید. خوانایی کلی کد را در نظر بگیرید.

راهنمایی جزیی: رد کردن یک ورودی خالی به prompt یک رشته خالی '' بر می گرداند. فشار دادن ESC در حین null prompt را بر می گرداند.

اجرای دمو

let userName = prompt("Who's there?", '');

if (userName === 'Admin') {

  let pass = prompt('Password?', '');

  if (pass === 'TheMaster') {
    alert( 'Welcome!' );
  } else if (pass === '' || pass === null) {
    alert( 'Canceled' );
  } else {
    alert( 'Wrong password' );
  }

} else if (userName === '' || userName === null) {
  alert( 'Canceled' );
} else {
  alert( "I don't know you" );
}

به تورفتگی عمودی درون بلوک های if توجه کنید. از لحاظ فنی به آنها نیازی نیست، اما کد را خواناتر می کنند.

نقشه آموزش