عبارت های شرطی در جاوا اسکریپت — راهنمای پیشرفته

۳۳۰ بازدید
آخرین به‌روزرسانی: ۰۸ شهریور ۱۴۰۲
زمان مطالعه: ۱۰ دقیقه
عبارت های شرطی در جاوا اسکریپت — راهنمای پیشرفته

عبارت های شرطی جنبه بسیار مهمی از ساختار هر زبان برنامه‌نویسی محسوب می‌شوند. اگر تاکنون به هر زبانی برنامه‌نویسی کرده باشید، احتمالاً با عبارت‌های شرطی مانند if..elif..else یا switch آشنا شده‌اید. این عبارت‌ها برای تصمیم‌گیری در برنامه‌ها نیز بسیار مهم هستند.

برای نمونه فرض کنید یک صندوق گنج طوری طراحی شده است که تنها صاحب آن بتواند صندوق را باز کند. این منطق را از لحاظ برنامه‌نویسی در زبان پایتون می‌توان به صورت زیر نمایش داد:

if person == 'Glad':
  # Open the treasure chest for Glad
  TreasureChest.open()

else:
  # Don't open the chest for any other person
TreasureChest.ignore()

با این که قطعه کد فوق به زبان پایتون نوشته شده است؛ اما این مقاله منحصراً در مورد جاوا اسکریپت است. با این وجود بیشتر تکنیک‌هایی که می‌بینید را می‌توان در هر زبان برنامه‌نویسی دیگری نیز استفاده کرد.

در ادامه این مقاله تنها مثال‌هایی از زبان برنامه‌نویسی جاوا ارائه خواهیم کرد. همچنین تأکید بیشتری را روی عبارت‌های شرطی با استفاده از عملگرهای منطقی (conditional expressions) در جاوا اسکریپت خواهیم داشت تا نشان دهیم که چگونه می‌توانیم با استفاده از آن‌ها کدی تمیزتر نسبت به گزاره‌های شرطی (onditional statements) داشته باشیم.

عبارت یا گزاره

پیش از ادامه باید تفاوت بین عبارت‌ها و گزاره‌ها در جاوا اسکریپت را روشن‌تر کنیم. به مقایسه بسیار ابتدایی زیر توجه کنید:

عبارت‌ها در جاوا اسکریپت مانند اصطلاح‌های یک زبان هستند؛ در حالی که گزاره‌ها در جاوا اسکریپت مانند جمله‌های یک زبان هستند.

منظور از عبارت، اصطلاحی است که موتور جاوا اسکریپت می‌تواند برای آن مقداری ارزیابی کند.

برای نمونه لفظ‌ها (literals)، انتساب‌ها، عبارت‌های تابعی، عملگرهای منطقی، بیتی یا حسابی، دسترسی مشخصات شیء، فراخوانی تابع‌ها، eval و غیره همگی عبارت هستند.

در قطعه کد زیر برخی از عبارت‌های زبان جاوا اسکریپت نمایش یافته است:

// number literal
0xFF

// array literal
[]

// object literal
{}

// regexp literal
/^\d+$/

// logical AND operation
(x && y)

// bitwise XOR operation
(x ^ y)

// ternary operation
(x ? y : z)

// arithmetic operation
(x + y) / z

// assignment
x = 'string'

// function expression
(function x(y) {})

// function invocation
x(100)

// object property access
obj.students[0].name

منظور از گزاره هر جمله یا دستوری است که موتور جاوا اسکریپت می‌تواند آن را اجرا کند تا کاری انجام دهد یا اثری جانبی ایجاد شود.

برای نمونه گزاره‌های شرطی، اعلان متغیر یا تابع، حلقه‌ها، throw، return، try/catch/finally و غیره همگی گزاره محسوب می‌شوند.

برخی عبارت‌های جاوا اسکریپت مانند انتساب‌ها و فراخوانی تابع‌ها می‌توانند اثرات جانبی داشته باشند و از این رو معمولاً به عنوان گزاره (عبارات گزاره‌ای) نگریسته می‌شوند.

شرط‌ها و مقادیر بولی

یکی از الزامات ضروری هر گزاره شرطی، خود شرط (condition) است. منظور از شرط، آن چیزی است که تعیین می‌کند برنامه باید چه کار کند.

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

داشتن درک صحیحی از شیوه تبدیل این عبارت‌های شرطی به مقادیر بولی از سوی موتور جاوا اسکریپت برای نوشتن منطق‌های شرطی صحیح و قابل پیش‌بینی امری ضروری به حساب می‌آید.

در ادامه دو مفهوم بنیادی که می‌توانند به ما کمک کنند تا این تبدیل‌ها را درک کنیم ارائه کرده‌ایم:

  • شناسایی مقادیر درست و نادرست
  • درک اتصال کوتاه در عملیات منطقی
  • مقادیر قابل تبدیل به درست یا نادرست

هر مقداری در جاوا اسکریپت را می‌توان به صورت یکی از مقادیر درست یا نادرست دسته‌بندی کرد. مقادیر نادرست در جاوا اسکریپت از قرار زیر هستند:

  • '' یا "" یا `` (رشته خالی)
  • 0 یا -0 (عدد صفر)
  • Null (تهی)
  • Undefined (تعریف نشده)
  • NaN (غیر عددی)
  • False (نادرست)

هر مقدار دیگری به جز آن‌ها که در فهرست فوق ارائه کردیم، مقدار درستی ارزیابی می‌شود. هر زمان که جاوا اسکریپت انتظار یک مقدار بولی داشته باشد، مقادیری که قابل تبدیل به مقدار درست یا نادرست باشند به این نوع تبدیل می‌شوند.

function toBoolean(value) {
  return Boolean(value);
}

می‌توان از عملگر منطقی NOT (!) نیز برای تبدیل یک مقدار به معادل بولی‌اش استفاده کرد. عملگر «!»، عملوندش را به مقدار بولی معکوس تبدیل می‌کند از این رو همواره برای ارزیابی یک مقدار بولی استفاده می‌شود. استفاده از عملگر «!» روی مقادیر درست به صورت false ارزیابی می‌شود و برعکس. برای تبدیل یک مقدار به معادل بولی‌اش باید از عملگر «!» دو بار استفاده کنید، یعنی به صورت «!!» استفاده شود.

function toBoolean(value) {
  return !!value;
}

اتصال کوتاه

هر دو عملگرهای منطقی AND (&&) و OR (||) به دو عملوند نیاز دارند و برای اجرای عملیات بولی روی عملوندها استفاده می‌شوند.

با فرض این که دو عملوند به صورت بولی (true یا flase) باشند، وضعیت‌های زیر وجود دارند:

عملیات && تنها زمانی مقدار true بازمی‌گرداند که هر دو عملوند true باشند، در غیر این صورت مقدار false بازمی‌گرداند.

عملیات || تنها زمانی مقدار false بازمی‌گرداند که هر دو عملوند false باشند، در غیر این صورت مقدار true بازمی‌گرداند.

توجه داشته باشید که عملگر && تقدم بالاتری نسبت به عملگر || دارد و بدین ترتیب معمولاً ابتدا مورد ارزیابی قرار می‌گیرد. از این رو زمانی که این دو با هم در یک عبارت استفاده شوند، اگر می‌خواهید تقدم آن‌ها را به صورت دستی تعیین کنید، باید از پرانتز برای گروه‌بندی استفاده کنید. قطعه کد زیر را در نظر بگیرید:

false && true || true; // true
false && (true || true); // false

زمانی که از این عملگرها استفاده می‌کنیم، عملوند اول همواره ارزیابی می‌شود. با این وجود، عملوند دوم ممکن است بسته به نتیجه حاصل از ارزیابی عملوند نخست، هرگز مورد ارزیابی قرار نگیرد. این رفتار به نام «اتصال کوتاه» (short-circuiting) نامیده می‌شود.

عملگرهای && و || همواره یک مقدار بولی ایجاد نمی‌کنند. به طور کلی این عملگرها می‌توانند هر مقداری را بازگردانند. در ادامه توصیف دقیق‌تری از رفتار عملگرها بر اساس اتصال کوتاه ارائه می‌کنیم:

عملگر && ابتدا عملوند نخست را ارزیابی می‌کند. اگر مقدار حاصل قابل تبدیل به درست باشد، متعاقباً اقدام به ارزیابی عملوند دوم می‌کند و مقدار آن را بازمی‌گرداند. با این وجود اگر مقدار عملوند نخست قابل تبدیل به نادرست باشد، عملوند دوم هرگز مورد ارزیابی قرار نمی‌گیرد و صرفاً مقدار نادرست از عملوند اول بازگشت می‌یابد.

(a && b) === a; // `a` is falsy
(a && b) === b; // `a` is truthy

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

(a || b) === a; // `a` is truthy
(a || b) === b; // `a` is falsy

جایگزینی عبارت‌ها به جای گزاره‌ها

اینک شما درک روشنی از مفهوم اتصال کوتاه و شیوه تبدیل عبارت‌های شرطی به مقادیر بولی دارید.

در ادامه روش تبدیل برخی از گزاره‌های شرطی به عبارت‌های ساده را بررسی می‌کنیم. همچنین خواهیم دید که چگونه استفاده از این تبدیل‌ها باعث می‌شود که کدتان فشرده و تمیزتر به نظر برسد.

گزاره‌های If ساده

گزاره‌های if بسیار ساده را می‌توان به کمک مفهوم اتصال کوتاه به عبارت‌های شرطی تبدیل کرد. قطعه کد زیر را ملاحظه کنید:

if (user && user.canDeletePost) {
  deletePost();
}

در قطعه کد فوق گزاره if برای حصول اطمینان از این است که تابع ()deletePost تنها زمانی فراخوانی می‌شود که شرط به صورت true باشد. گزاره if ساده را می‌توان با عبارت بسیار ساده شرطی نمایش یافته در کد زیر جایگزین کرد:

user && user.canDeletePost && deletePost();

با این که عبارت شرطی فوق به روشی مشابه با گزاره if قبلی عمل می‌کند؛ اما در عمل متفاوت از هم هستند.

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

به خاطر داشته باشید که استفاده از عبارت‌های شرطی مانند این، بدان معنی است که به طور کامل مسئله اتصال کوتاه را در نظر گرفته‌اید. همان‌طور که در بخش قبلی در مورد اتصال کوتاه مشاهده کردیم، همواره این احتمال وجود دارد که یک عملوند مورد ارزیابی قرار نگیرد.

گزاره‌های If…Else

به قطعه کد زیر که برای بررسی میزان قوی بودن یک رمز عبور نوشته شده است، توجه کنید:

let strength = null;

if (password.length > 7) {
  strength = 'Strong';
} else {
  strength = 'Weak';
}

مقصود قطعه کد فوق بسیار ساده است و می‌خواهد بررسی کند که آیا رمز عبور بیش از 7 کاراکتر طول دارد یا نه. اگر چنین باشد، متغیر strength به صورت «Strong» و در غیر این صورت به مقدار «Weak» تعیین می‌شود.

قطعه کد قبلی را می‌توان به صورت زیر خلاصه کرد:

const strength = (password.length > 7) && 'Strong' || 'Weak';

قطعه کد فوق دقیقاً همان کار کد قبلی را در یک خط انجام می‌دهد. این وضعیت کاملاً مناسب است. قطعه کد زیر تلاش می‌کند تا ارزیابی عبارت شرطی را مورد بازنگری قرار دهد:

let password = 'long_password';

console.log(password.length > 7); // true
console.log(password.length > 7 && 'Strong'); // "Strong"
console.log(password.length > 7 && 'Strong' || 'Weak'); // "Strong"

password = 'short';

console.log(password.length > 7); // false
console.log(password.length > 7 && 'Strong'); // false
console.log(password.length > 7 && 'Strong' || 'Weak'); // "Weak"

البته روشی بهتر از این هم برای نوشتن این نوع عبارت‌های شرطی if...else با استفاده از عملگر شرطی وجود دارد که عملگر سه‌تایی (ternary operator) نامیده می‌شود. ساختار آن مانند زیر است:

// If condition is truthy, evaluate and return A,
// otherwise evaluate and return B

condition ? A : B

قطعه کد فوق را می‌توان با استفاده از عملگر سه‌تایی به صورت زیر نوشت:

const strength = (password.length > 7)? 'Strong': 'Weak';

با این که این قطعه کد فوق با استفاده از عملگرهای منطقی به روشی مشابه قطعه کد نوشته شده با عملگر سه‌تایی عمل می‌کند؛ اما باید بدانید که این دو قابل جایگزینی با هم نیستند.

استفاده از عملگر سه‌تایی در مواردی مانند این بسیار امن‌تر است؛ مگر این که واقعاً بدانید چه کار انجام می‌دهید.

قطعه کد زیر را برای درک خطرات استفاده از عملگرهای منطقی برای چنین مواردی در نظر بگیرید:

// LOGICAL OPERATORS
// If condition is truthy and A is truthy, return A,
// otherwise evaluate and return B

// Danger: A will never be returned if it is falsy

condition && A || B


// TERNARY OPERATOR
// If condition is truthy, evaluate and return A,
// otherwise evaluate and return B

condition ? A : B

این کد گزاره شرطی بسیار متداولی را نشان می‌دهد که معمولاً در کتابخانه‌های چند مرورگری AJAX یافت می‌شود.

let xmlhttp = null;

if (window.XMLHttpRequest) {
  
  // Modern browsers
  xmlhttp = new XMLHttpRequest();
  
} else if (window.ActiveXObject) {
  
  // Older versions of Internet Explorer (IE <= 6)
  xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
  
}

قطعه کد فوق را با استفاده از عملگرهای سه‌تایی می‌توان به صورت زیر نوشت (دقت کنید که تورفتگی‌ها برای ایجاد خوانایی هستند):

const xmlhttp = window.XMLHttpRequest && new XMLHttpRequest()
  || window.ActiveXObject && new ActiveXObject('Microsoft.XMLHTTP')
|| null;

با این وجود، کد فوق را با استفاده از عملگر سه‌تایی می‌توان به صورت زیر نوشت:

const xmlhttp = window.XMLHttpRequest
  ? new XMLHttpRequest()
  : window.ActiveXObject
    ? new ActiveXObject('Microsoft.XMLHTTP')
: null;

دقت کنید که در قطعه کد، فوق عملگر سه‌تایی به صورت تو در تو است که برای بررسی شرایط if...else پیچیده‌تر مناسب است.

نکات و میان‌برها

در این بخش از مقاله حاضر، برخی نکات مفید و میانبرهایی که هنگام کار با شرط‌ها و عملگرهای منطقی مفید خواهند بود را معرفی می‌کنیم.

نرمالسازی به صورت مقادیر بولی

در بخش‌های قبلی دیدیم که چگونه می‌توان به طور صریح یک مقدار جاوا اسکریپت را از طریق استفاده از تابع Boolean بومی یا با استفاده از عملگرهای دوگانه NOT (!!) به معادل بولی‌اش تبدیل کرد.

فرض کنید می‌خواهید مقدار value را طوری نرمال‌سازی کنید که همواره مقدار بولی به صورت زیر داشته باشید:

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

قطعه کد زیر روش انجام این کار را نشان می‌دهد (دقت کنید که بدین منظور از تابع استفاده شده است):

// boolOrFalse()
// Return value if it is a boolean,
// otherwise return false

const boolOrFalse = value => {
  return (typeof value === 'boolean') && value;
}

console.log(boolOrFalse()); // false
console.log(boolOrFalse(0)); // false
console.log(boolOrFalse('')); // false
console.log(boolOrFalse(false)); // false
console.log(boolOrFalse(true)); // true


// boolOrTrue()
// Return value if it is a boolean,
// otherwise return true

const boolOrTrue = value => {
  return (typeof value !== 'boolean') || value;
}

console.log(boolOrTrue()); // true
console.log(boolOrTrue(0)); // true
console.log(boolOrTrue('')); // true
console.log(boolOrTrue(false)); // false
console.log(boolOrTrue(true)); // true

قواعد دمورگان

اگر با جبر بولی آشنایی داشته باشید، احتمالاً در مورد قواعد دمورگان اطلاعاتی دارید. این قواعد در مورد عملگرهای منطقی جاوا اسکریپت نیز کاربرد دارند. قطعه کد زیر این قواعد را نشان می‌دهد:

// These two are equivalent
!A && !B == !(A || B)

// Also these two
!A || !B == !(A && B)

نهادهای بولی

زمانی که با مقادیر بولی سر و کار داریم، برخی نهادهای مشخص وجود دارند که همواره مقدار true دارند. با فرض این که A، B و C مقادیر بولی باشند، قطعه کد زیر برخی از این نهادها را نمایش می‌دهد:

// NOT Conversion
!!A == A
!!B == B
!!C == C

// AND to OR Conversion
A && B == !(!A || !B)

// OR to AND Conversion
A || B == !(!A && !B)

// Removing nested AND
A || (B && C) == A || B && C

// Removing nested OR
A && (B || C) == !(!A || !B && !C)

عملگرهای سه‌تایی چندگانه

در قطعه کدهای قبلی مشاهده کردید که عملگرهای سه‌تایی می‌توانند به صورت تودرتو برای مدیریت منطق‌های شرطی if...else پیچیده‌تر مورد استفاده قرار گیرند.

با این وجود، چند نکته هستند که باید در مورد تقدم و شرکت‌پذیری عملگر سه‌تایی بدانید تا بتوانید از آن به طرز مؤثرتری در عبارت‌های پیچیده استفاده کنید.

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

// this expression
A ? B + C && D : E || F && G

// will be evaluated as
A ? ((B + C) && D) : (E || (F && G))

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

// this expression
A ? B : C ? D : E ? F : G

// will be evaluated as
(A ? B : (C ? D : (E ? F : G)))

وقتی از عملگر سه‌تایی چندگانه در یک عبارت استفاده می‌کنید، ممکن است لازم باشد که از پرانتز برای تغییر دادن ترتیب ارزیابی استفاده کنید. مثالی از آن را در ادامه می‌بینید:

// this expression
A ? B : (C ? D : E) ? F : G

// will be evaluated as
(A ? B : ((C ? D : E) ? F : G))

سخن پایانی

اینک به پایان مطالعه این مقاله رسیده‌اید، مطمئناً قادر هستید مواردی را که نکات و تکنیک‌های معرفی شده در این مقاله در کدهایتان قابل استفاده هستند تشخیص دهید و بدین ترتیب مانند یک برنامه‌نویس خبره کدهای خود را بهبود دهید.

اگر این مطلب برایتان مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
hackernoon
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *