نکاتی برای بهتر نوشتن شرط‌ها در جاوااسکریپت

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

۱. استفاده از Array.includes:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// condition
function test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}
}
// condition function test(fruit) { if (fruit == 'apple' || fruit == 'strawberry') { console.log('red'); } }
// condition
function test(fruit) {
  if (fruit == 'apple' || fruit == 'strawberry') {
    console.log('red');
  }
}

در اولین نگاه مثال بالا خوب به نظر می‌رسد. اما اگر بخواهیم تعداد میوه‌ها را زیاد کنیم، آیا این راه حل درستی است؟ یعنی به ازای هر میوه باید یک عملگر “یا” به شرط اضافه کنیم. خوب در این جا بهتر است که با استفاده از متد includes() کد را بازنویسی کنیم.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit) {
// extract conditions to array
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}
}
function test(fruit) { // extract conditions to array const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; if (redFruits.includes(fruit)) { console.log('red'); } }
function test(fruit) {
  // extract conditions to array
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  if (redFruits.includes(fruit)) {
    console.log('red');
  }
}

در این جا شرط را به داخل آرایه redFruits بردیم. با انجام این کار، کد ساده‌تر خواهد شد. متد includes() تعیین می‌کند که آرایه حاوی یک عنصر خاص است یا خیر  که به ترتیب آن را با true یا false بر می‌گرداند.

۲. شرط‌های تو در توی کمتر، بازگشت سریع‌تر:

به مثال قبلی دو تا شرط  زیر را اضافه کنید:

  • اگر هیچ میوه‌ای نداشتیم خطا بدهد
  • اگر بیش از ۱۰ عدد میوه باشد، مقدار آن را هم چاپ کند
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// condition 1: fruit must has value
if (fruit) {
// condition 2: must be red
if (redFruits.includes(fruit)) {
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
} else {
throw new Error('No fruit!');
}
}
// test results
test(null); // error: No fruits
test('apple'); // print: red
test('apple', 20); // print: red, big quantity
function test(fruit, quantity) { const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; // condition 1: fruit must has value if (fruit) { // condition 2: must be red if (redFruits.includes(fruit)) { console.log('red'); // condition 3: must be big quantity if (quantity > 10) { console.log('big quantity'); } } } else { throw new Error('No fruit!'); } } // test results test(null); // error: No fruits test('apple'); // print: red test('apple', 20); // print: red, big quantity
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  // condition 1: fruit must has value
  if (fruit) {
    // condition 2: must be red
    if (redFruits.includes(fruit)) {
      console.log('red');

      // condition 3: must be big quantity
      if (quantity > 10) {
        console.log('big quantity');
      }
    }
  } else {
    throw new Error('No fruit!');
  }
}

// test results
test(null); // error: No fruits
test('apple'); // print: red
test('apple', 20); // print: red, big quantity

در کد بالا ، با استفاده از عبارت if/else در ۳ لایه ، شرط تو در تو داریم.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// condition 1: throw error early
if (!fruit) throw new Error('No fruit!');
// condition 2: must be red
if (redFruits.includes(fruit)) {
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
}
function test(fruit, quantity) { const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; // condition 1: throw error early if (!fruit) throw new Error('No fruit!'); // condition 2: must be red if (redFruits.includes(fruit)) { console.log('red'); // condition 3: must be big quantity if (quantity > 10) { console.log('big quantity'); } } }
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  // condition 1: throw error early
  if (!fruit) throw new Error('No fruit!');

  // condition 2: must be red
  if (redFruits.includes(fruit)) {
    console.log('red');

    // condition 3: must be big quantity
    if (quantity > 10) {
      console.log('big quantity');
    }
  }
}

با انجام این کار یک لایه غیر ضروری شرط را کاهش می‌دهیم. این استایل برای کد مناسب است، مخصوصا وقتی عبارت if طولانی داشته باشیم. در غیر این صورت شاید مجبور باشیم برای پیدا کردن else به پایین اسکرول کنیم.

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (!fruit) throw new Error('No fruit!'); // condition 1: throw error early
if (!redFruits.includes(fruit)) return; // condition 2: stop when fruit is not red
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
function test(fruit, quantity) { const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; if (!fruit) throw new Error('No fruit!'); // condition 1: throw error early if (!redFruits.includes(fruit)) return; // condition 2: stop when fruit is not red console.log('red'); // condition 3: must be big quantity if (quantity > 10) { console.log('big quantity'); } }
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];

  if (!fruit) throw new Error('No fruit!'); // condition 1: throw error early
  if (!redFruits.includes(fruit)) return; // condition 2: stop when fruit is not red

  console.log('red');

  // condition 3: must be big quantity
  if (quantity > 10) {
    console.log('big quantity');
  }
}

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

بنابراین همیشه هدف کمتر کردن شرط‌های تو در تو و بازگشت سریع است. اما توجه داشته باشید که استفاده  بیش از حد آن شاید باعث سردرگمی شود.

اگر به این موضوع علاقه‌مند هستید، در این لینک بیشتر درباره این موضوع صحبت شده است.

۳. استفاده از پارامترهای تابع پیش فرض و destruct:

به احتمال زیاد کد زیر برای شما آشنا به نظر برسد. وقتی با جاوااسکریپت کار می‌کنید، همیشه نیاز است که مقدار null/undefined چک شود و مقدار پیش فرضی به آن اختصاص دهید.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit, quantity) {
if (!fruit) return;
const q = quantity || 1; // if quantity not provided, default to one
console.log(`We have ${q} ${fruit}!`);
}
//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
function test(fruit, quantity) { if (!fruit) return; const q = quantity || 1; // if quantity not provided, default to one console.log(`We have ${q} ${fruit}!`); } //test results test('banana'); // We have 1 banana! test('apple', 2); // We have 2 apple!
function test(fruit, quantity) {
  if (!fruit) return;
  const q = quantity || 1; // if quantity not provided, default to one

  console.log(`We have ${q} ${fruit}!`);
}

//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

می‌توانیم متغییر q را با اختصاص دادن پارامترهای پیش فرض تخمین بزنیم.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit, quantity = 1) { // if quantity not provided, default to one
if (!fruit) return;
console.log(`We have ${quantity} ${fruit}!`);
}
//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
function test(fruit, quantity = 1) { // if quantity not provided, default to one if (!fruit) return; console.log(`We have ${quantity} ${fruit}!`); } //test results test('banana'); // We have 1 banana! test('apple', 2); // We have 2 apple!
function test(fruit, quantity = 1) { // if quantity not provided, default to one
  if (!fruit) return;
  console.log(`We have ${quantity} ${fruit}!`);
}

//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

توجه کنید که هر پارامتر می‌تواند پارامتر تابع پیش فرض خود را داشته باشد. به طور مثال می‌توانیم مقدار پیش فرض را به صورت زیر به fruit اختصاص دهیم.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit = 'unknown', quantity = 1)
function test(fruit = 'unknown', quantity = 1)
function test(fruit = 'unknown', quantity = 1)

حالا اگر fruit یک آبجکت باشد، چگونه می توانیم پارامتر پیش فرض را تعیین کنیم؟

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(fruit) {
// printing fruit name if value provided
if (fruit && fruit.name) {
console.log (fruit.name);
} else {
console.log('unknown');
}
}
//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
function test(fruit) { // printing fruit name if value provided if (fruit && fruit.name) { console.log (fruit.name); } else { console.log('unknown'); } } //test results test(undefined); // unknown test({ }); // unknown test({ name: 'apple', color: 'red' }); // apple
function test(fruit) { 
  // printing fruit name if value provided
  if (fruit && fruit.name)  {
    console.log (fruit.name);
  } else {
    console.log('unknown');
  }
}

//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

به مثال بالا نگاه کنید. ما می‌خواهیم fruit.name را چاپ کنیم. اگر مقدار داشت اسم میوه را چاپ کند و اگر مقدار نداشت، unknown را چاپ کند.

با استفاده از پارامتر تابع پیش فرض و destruct، می‌توانیم شرط (fruit && fruit.name) را حذف کنیم.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// destructing - get name property only
// assign default empty object {}
function test({name} = {}) {
console.log (name || 'unknown');
}
//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
// destructing - get name property only // assign default empty object {} function test({name} = {}) { console.log (name || 'unknown'); } //test results test(undefined); // unknown test({ }); // unknown test({ name: 'apple', color: 'red' }); // apple
// destructing - get name property only
// assign default empty object {}
function test({name} = {}) {
  console.log (name || 'unknown');
}

//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

دستور destruct در جاوااسکریپت، مقدار آرایه‌ها و آبجکت‌های اختصاص داده شده را از هم مجزا می‌کند.

از آنجایی که ما فقط به خاصیت name از fruit نیاز داریم، می‌توانیم با استفاده از پارامتر {name ،{name را به عنوان متغییر در کد به جای fruit.name به کار ببریم.

ما همچنین آبجکت خالی {} را به عنوان مقدار پیش فرض اختصاص می‌دهیم. اگر این کار را انجام ندهیم خطای Undefined را دریافت می‌کنیم.

روش دیگر استفاده از تابع get در loadash است. کتابخانه loadash آرایه، رشته و آرگومان را پشتیبانی می‌کند. مقدار name را از آبجکت fruit می‌گیرد. اگر مقدار آن تعریف نشده باشد مقدار defaultValue را بر می‌گرداند.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Include lodash library, you will get _
function test(fruit) {
console.log(__.get(fruit, 'name', 'unknown'); // get property name, if not available, assign default value 'unknown'
}
//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
// Include lodash library, you will get _ function test(fruit) { console.log(__.get(fruit, 'name', 'unknown'); // get property name, if not available, assign default value 'unknown' } //test results test(undefined); // unknown test({ }); // unknown test({ name: 'apple', color: 'red' }); // apple
// Include lodash library, you will get _
function test(fruit) {
  console.log(__.get(fruit, 'name', 'unknown'); // get property name, if not available, assign default value 'unknown'
}

//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

۴. متد Map و Object Literal نسبت به عبارت switch:

در این جا می‌خواهیم میوه‌ها را بر اساس رنگ چاپ کنیم.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function test(color) {
// use switch case to find fruits in color
switch (color) {
case 'red':
return ['apple', 'strawberry'];
case 'yellow':
return ['banana', 'pineapple'];
case 'purple':
return ['grape', 'plum'];
default:
return [];
}
}
//test results
test(null); // []
test('yellow'); // ['banana', 'pineapple']
function test(color) { // use switch case to find fruits in color switch (color) { case 'red': return ['apple', 'strawberry']; case 'yellow': return ['banana', 'pineapple']; case 'purple': return ['grape', 'plum']; default: return []; } } //test results test(null); // [] test('yellow'); // ['banana', 'pineapple']
function test(color) {
  // use switch case to find fruits in color
  switch (color) {
    case 'red':
      return ['apple', 'strawberry'];
    case 'yellow':
      return ['banana', 'pineapple'];
    case 'purple':
      return ['grape', 'plum'];
    default:
      return [];
  }
}

//test results
test(null); // []
test('yellow'); // ['banana', 'pineapple']

این کد به نظر می رسد که هیچ ایرادی ندارد. ما می توانیم با استفاده از object literal همان نتیجه را بدست بیاوریم ولی درعوض کد تمیزتری داشته باشیم. همان طور که می دانید object literal یکی از روش های ایجاد آبجکت در جاوا اسکریپت است که مقدار key ، value ها داخل {} قرار می گیرند.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// use object literal to find fruits in color
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function test(color) {
return fruitColor[color] || [];
}
// use object literal to find fruits in color const fruitColor = { red: ['apple', 'strawberry'], yellow: ['banana', 'pineapple'], purple: ['grape', 'plum'] }; function test(color) { return fruitColor[color] || []; }
// use object literal to find fruits in color
  const fruitColor = {
    red: ['apple', 'strawberry'],
    yellow: ['banana', 'pineapple'],
    purple: ['grape', 'plum']
  };

function test(color) {
  return fruitColor[color] || [];
}

همچنین می‌توان با استفاده از map به همان نتیجه  رسید. آبجکت map برای ES6 در دسترس است و key و value آن را می‌توانید ذخیره کنید. آبجکت map عناصر خود را مثل حلقه for و بر اساس آرایه [key, value] تکرار می‌شود.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// use Map to find fruits in color
const fruitColor = new Map()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'plum']);
function test(color) {
return fruitColor.get(color) || [];
}
// use Map to find fruits in color const fruitColor = new Map() .set('red', ['apple', 'strawberry']) .set('yellow', ['banana', 'pineapple']) .set('purple', ['grape', 'plum']); function test(color) { return fruitColor.get(color) || []; }
// use Map to find fruits in color
  const fruitColor = new Map()
    .set('red', ['apple', 'strawberry'])
    .set('yellow', ['banana', 'pineapple'])
    .set('purple', ['grape', 'plum']);

function test(color) {
  return fruitColor.get(color) || [];
}

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'strawberry', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'pineapple', color: 'yellow' },
{ name: 'grape', color: 'purple' },
{ name: 'plum', color: 'purple' }
];
function test(color) {
// use Array filter to find fruits in color
return fruits.filter(f => f.color == color);
}
const fruits = [ { name: 'apple', color: 'red' }, { name: 'strawberry', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'pineapple', color: 'yellow' }, { name: 'grape', color: 'purple' }, { name: 'plum', color: 'purple' } ]; function test(color) { // use Array filter to find fruits in color return fruits.filter(f => f.color == color); }
const fruits = [
    { name: 'apple', color: 'red' }, 
    { name: 'strawberry', color: 'red' }, 
    { name: 'banana', color: 'yellow' }, 
    { name: 'pineapple', color: 'yellow' }, 
    { name: 'grape', color: 'purple' }, 
    { name: 'plum', color: 'purple' }
];

function test(color) {
  // use Array filter to find fruits in color

  return fruits.filter(f => f.color == color);
}

 ۵. از Array.every  و Array.some استفاده کنید:

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
let isAllRed = true;
// condition: all fruits must be red
for (let f of fruits) {
if (!isAllRed) break;
isAllRed = (f.color == 'red');
}
console.log(isAllRed); // false
}
const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { let isAllRed = true; // condition: all fruits must be red for (let f of fruits) { if (!isAllRed) break; isAllRed = (f.color == 'red'); } console.log(isAllRed); // false }
const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
  ];

function test() {
  let isAllRed = true;

  // condition: all fruits must be red
  for (let f of fruits) {
    if (!isAllRed) break;
    isAllRed = (f.color == 'red');
  }

  console.log(isAllRed); // false
}

کد ما این جا خیلی طولانی است می توانیم با استفاده از متدهای every و some  کدهای کوتاهتر و تمیزتری  داشته باشیم.

با متد every() می توانیم چک کنیم که آیا همه میوه ها رنگشان قرمز است یا نه ، در این متد باید همه عناصر آرایه ، شرط مورد نظر را داشته باشند تا true برگرداند.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// condition: short way, all fruits must be red
const isAllRed = fruits.every(f => f.color == 'red');
console.log(isAllRed); // false
}
const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { // condition: short way, all fruits must be red const isAllRed = fruits.every(f => f.color == 'red'); console.log(isAllRed); // false }
const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
  ];

function test() {
  // condition: short way, all fruits must be red
  const isAllRed = fruits.every(f => f.color == 'red');

  console.log(isAllRed); // false
}

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// condition: if any fruit is red
const isAnyRed = fruits.some(f => f.color == 'red');
console.log(isAnyRed); // true
}
const fruits = [ { name: 'apple', color: 'red' }, { name: 'banana', color: 'yellow' }, { name: 'grape', color: 'purple' } ]; function test() { // condition: if any fruit is red const isAnyRed = fruits.some(f => f.color == 'red'); console.log(isAnyRed); // true }
const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
];

function test() {
  // condition: if any fruit is red
  const isAnyRed = fruits.some(f => f.color == 'red');

  console.log(isAnyRed); // true
}

 

منبع: scotch.io

دیدگاه‌ها:

افزودن دیدگاه جدید