برنامه‌نویسی

ترفندهایی برای نوشتن کدهای کوتاه در JavaScript


۲۶ فروردین ۱۴۰۰
ترفندهایی برای نوشتن کدهای کوتاه در javascript

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

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

۱) بررسی مقادیر Null، Undefined و Empty

مطمئنا برای توسعه‌ی یک برنامه‌ی ایمن‌تر همیشه بررسی می‌کنیم که مقدار متغیر ما هیچکدام از موارد Null، Undefined و Empty نباشد و به‌همین دلیل در اولین ترفند می‌خواهیم به این موضوع بپردازیم.

احتمالا اولین کدی که برای بررسی مقادیر Null، Undefined و Empty به‌ذهن شما می‌رسد به‌شکل زیر است:

// Longhand version
if (productName !== undefined || productName !== "" || productName !== null) {
    console.log(productName)
}

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

// Shorthand version
if (productName) {
    console.log(productName)
}

۲) شروط چندگانه

اغلب ممکن است از شروط چندگانه‌ای مانند مثال زیر استفاده کنیم:

//longhand
if (x === 'orange' || x === 'red' || x === 'gray') {
    // do something
}

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

//shorthand
if (['orange', 'red', 'gray'].includes(x)) {
    // do something
}

۳) حلقه‌ها

حلقه‌ها نیز از مواردی هستند که قطعا در همه‌ی برنامه‌ها از آن‌ها استفاده می‌کنیم و در این بخش می‌خواهیم به این موضوع بپردازیم که چگونه حلقه‌های خود را هوشمندانه‌تر بنویسیم:

//longhand
for (var i = 0; i < productsList.length; i++) {
    // do things
}

//shorthand (to access the index)
for (let i in productsList) {
    // do things
}
// or (to access productsList's elements)
for (let i of productsList) {
    // do things
}

// or with foreach
productsList.forEach(element => {
    // do things
});

۴) Implicit returns

implicit returns به این شکل است که فانکشن شما بدون استفاده از کلمه‌‌ی کلیدی return یک مقدار را برمی‌گرداند. حال برای تبدیل یک فانکشن عادی مانند مثال زیر:

//longhand
function getProductPrice() {
    return quantity * productPrice;
}

می‌توانیم از Arrow Function استفاده کنیم که به ما اجازه می‌دهد بدون استفاده از کلمه‌ی کلیدی return، مقدار مورد نظر خود را برگردانیم:

//shorthand 
getProductPrice = price => quantity * productPrice;

۵) Spread

زمانی که می‌خواهیم آرایه‌ها را دستکاری کنیم استفاده از عملگر Spread اهمیت پیدا می‌کند. برای درک این موضوع به مثال زیر دقت کنید:

const team = ['John', 'Adam', 'Yan'];

//longhand 
//- joining
const group = ['Sam', 'Chris', 'Sarah'].concat(team);
//- cloning
const newGroup = team.slice();

در مثال فوق برای اضافه کردن آرایه team به آرایه group از concat() و علاوه‌برآن از slice() برای ایجاد یک clone از آرایه team استفاده شده است. حال به مثال زیر دقت کنید تا نحوه‌ی استفاده از ... یا همان عملگر Spread را متوجه شوید:

const team = ['John', 'Adam', 'Yan'];

//shorthand 
//- joining
const group = ['Sam', 'Chris', 'Sarah', ...team];
//- cloning
const newGroup = [...team];

۶) Arrow Function

باتشکر از ES6 می‌توانیم فانکشن‌های سنتی را به‌صورت ساده و با کدنویسی کم‌تر بنویسیم:

//longhand
function welcomeMessage(name) {
    console.log('Welcome ', name);
}
//shorthand
welcomeMessage = name => console.log(name);

۷) Template Literals

بسیاری از توسعه‌دهندگان هنوز هم از کاراکتر + برای ادغام یک رشته‌ی متنی و متغیر موردنظرشان استفاده می‌کنند اما با بهره‌گیری از ES6 می‌توانیم این کار را با استفاده از ${} و ` انجام دهیم.

// longhand
const winnerMsg = 'Congrats to the winner: ' + winnerName + ', you got a ' + gift;
// shorthand
const winnerMsg = `Congrats to the winner: ${winnerName}, you got a ${gift}`;

۸) رشته‌های چند خطی

برای اینکه نیازی نباشد در رشته‌های متنی خود از \n، \t یا موارد این‌چنینی استفاده کنید، یک راه حل وجود دارد:

// Longhand
const msg = 'Working in conjunction with humanitarian aid agencies,\n\t'
    + 'we have supported programmes to help alleviate human suffering. \n\t';

//Shorthand
const msg = `Working in conjunction with humanitarian aid agencies,
we have supported programmes to help alleviate human suffering.`;

۹) متد find() در آرایه‌ها

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

const animals = [
    { name: 'octopus', animalClass: 'invertebrates' },
    { name: 'shark', animalClass: 'fish' },
    { name: 'toad', animalClass: 'amphibians' },
    { name: 'snake', animalClass: 'reptiles' }
];


//Longhand
function findReptile(name) {
    for (let i = 0; i < animals.length; ++i) {
        if (animals[i].animalClass === 'reptiles' && animals[i].name === name) {
            return animals[i]
        }
    }
}

// Shorthand
findReptile = name => (
    animals.find(animal => animal.animalClass === 'reptiles' && animal.name === name)
)

۱۰) Nullish Coalescing

در بخش Spread Operator به یکی از جالب‌ترین عملگرها در زبان JavaScript پرداختیم و از این بخش به بعد می‌خواهیم عملگرهای دیگری را بررسی کنیم که در کوتاه نوشتن کدهای JavaScript به ما کمک می‌کنند.

سینتکس عملگر Nullish Coalescing به شکل زیر است:

a??b

خروجی کد فوق به این صورت است که اگر متغیر a تعریف شده باشد، آن را در خروجی دریافت می‌کنیم اما درصورتی که a تعریف نشده باشد یا مقدار آن null و undefined باشد بنابراین خروجی ما مقدار b خواهد بود.

به‌عبارت دیگر می‌توانیم بگوییم که با استفاده از ?? درصورتی که اولین پارامتر تعریف شده باشد و مقدار آن null یا undefined نباشد، همان پارامتر اول به ما return می‌شود اما درغیر این‌صورت پارامتر دوم به ما return خواهد شد.

برای درک بهتر این موضوع می‌توانید به مثال‌های زیر دقت کنید:

let a=NULL
console.log(a??50) //50
console.log(a) //NULL
let a=10
let c=30
console.log(a??b??c??d) //10
//gives output, the first defined value

۱۱) Logical Nullish Assignment

عملگر دیگری که به سراغ بررسی آن می‌رویم، Logical Nullish Assignment است و سینتکسی مشابه با عملگر Nullish Coalescing دارد که عملگر assignment یا همان = به آن اضافه شده است:

a??=b

همچنین یک معادل برای سینتکس این عملگر وجود دارد:

a??(a=b)

احتمالا با مشاهده‌ی سینتکس فوق می‌توانید به دیدگاه کامل‌تری از عملکرد این عملگر دست پیدا کنید. اگر مقدار a با null یا undefined برابر نباشد، آن‌موقع مقدار b به ما return می‌شود و درغیر این‌صورت مجددا مقدار b به ما return می‌شود با این تغییر که مقدار b در متغیر a ریخته خواهد شد.

برای درک بهتر این موضوع به مثال زیر توجه کنید:

let a=NULL
console.log(a??=50) //50
console.log(a) //50
//compare the output of a from the previous example.

۱۲) Optional Chaining

عملگر Optional Chaining کاربرد بسیار جالبی دارد. مطمئنا همه‌ی شما برای دریافت یک prop از object مورد نظرتان به این شکل زیر عمل می‌کنید:

obj.prop

اما این احتمال وجود دارد که prop مورد نظر در obj وجود نداشته باشد. حال با استفاده از این عملگر که سینتکس آن به‌شکل زیر است:

obj ?. prop

می‌توانیم از رخ دادن خطای TypeError در برنامه جلوگیری کنیم. عملکرد ?. به این صورت است که اگر مقدار مورد نظر ما موجود باشد، آن را به ما return می‌کند اما اگر مقدار مورد نظر ما در obj به‌صورت undefined یا null باشد مقدار undefined به ما return می‌شود.

روش دیگری نیز وجود دارد که ما می‌توانیم null یا undefined بودن object را نیز بررسی کنیم و آن هم این است که از عملگر . استفاده کنیم. مثلا اگر به صورت زیر عمل کنیم:

obj . prop

از null یا undefined نبودن obj قبل از اینکه بخواهیم به prop مورد نظر دسترسی بگیریم، مطمئن خواهیم شد. برای درک بهتر این موضوع‌ها بهتر است برای مطالعه‌ی مثال زیر وقت بگذارید:

let obj= {
   person:{
       firstName:"John",
       lastName:"Doe"
   },

   occupation: {
       compony:'capscode',
       position:'developer'
   },
   fullName: function(){
       console.log("Full Name is: "+ this.person.firstName+" >"+this.person.lastName)
  }
}
console.log(obj . person . firstName) //John
console.log(obj . human . award) //TypeError: Cannot read property 'award' of undefined
console.log(obj ?. human . award) //TypeError: Cannot read property 'award' of undefined
console.log(obj . human ?. award) //undefined
delete obj?.firstName;  // delete obj.firstName if obj exists
obj . fullName ?. () //logs John Doe
obj ?. fullName() //logs John Doe
obj . fullDetails() // TypeError: obj.fullDetails is not a function
obj ?. fullDetails() // TypeError: obj.fullDetails is not a function
obj.fullDetails ?. () //undefined