best practiceهایی برای نوشتن متغیرهای با کیفیت‌تر در جاوا اسکریپت

best practiceهایی برای نوشتن متغیرهای با کیفیت‌تر در جاوا اسکریپت

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

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

1. استفاده از const به جای let

برای تعریف متغیرها در جاوااسکریپت سه راه مختلف وجود داره. استفاده از var یا let یا const.
استفاده از var به نوعی منسوخ شده. در اصل let و const جایگزین‌های var هستن که از ES6 اضافه شدن و تا قبل از اون تنها راه تعریف متغیرها استفاده از var بود. تفاوت اصلی بین این دو اینه که متغیر const به یک مقدار اولیه نیاز داره و مقدار اون پس از مقداردهی اولیه قابل تخصیص مجدد نیست.

// initialization
const pi = 3.14;
// const variable con't be assigned
pi = 4.89; // "typeError: Assignment to constant variable"

اما let نیازمند مقداردهی اولیه نیست و مقدار اون هم هر زمان که نیاز بود میتونه تغییر کنه.

// initialization is optional
const output;
// let variable can reassigne
output = 14;
output = output * 2; // 28

همونطور که دیدیم const متغیری هست که یک بار مقدار میگیره (در مقایسه با let)، و این موضوع تصمیم گیری رو برای ما آسون تر میکنه چون میدونیم که مقدار اون تغییر نمیکنه.

بهتره که هنگام تعریف نوع متغیر ها همیشه از const استفاده کنید مگر زمانیکه متغیر نیاز به تغییر مقدار یا در طول اجرای کد نیاز به انتساب دوباره داشت؛ تنها در این صورت برای جلوگیری از خطا از let استفاده کنید. به تابع زیر دقت کنید:

function myFunction(param) {
    /* lots of codes... */
    const result = anotherFunction(param);
    /* lots of codes... */
    return something;
}

اگر به بدنه تابع دقت کنید متوجه const میشید. بدون اینکه از اتفاقی که درون تابع می‌افته خبر داشته باشید، میتونید نتیجه بگیرید متغیر result یک بار مقداردهی میشه و فقط هم قابل خوندن هست. این اتفاق خوانایی کد رو بیشتر کرده و همچنین اگه ناخواسته مقدار متغیر رو تغییر بدیم با ارور مواجه میشیم. در موارد دیگه اگه متغیر شما در طول اجرای کد نیاز به مقداردهی چند باره (re-assign) داشت، استفاده از let توصیه میشه.

2. قلمرو متغیر رو کوچک کنید.

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

یک بلاک کد یا بدنه‌ی یک تابع، قلمرویی برای متغیرهای const و let می‌سازن.

یک تمرین خوب برای افزایش خوانایی متغیرها اینه که اون‌ها رو در کوچکترین قلمرو ممکن نگهداری کنیم.

برای مثال، تابع زیر مربوط به جستجوی دودویی یا binary search هست:

function binarySearch(array, search) {
    let middle;
    let middleItem;
    let left = 0;
    let right = array.lengh - 1;

    while(left <= right) {
        middle = Math.floor((left + right) / 2 );
        middleItem = array[middle];
        if (middleItem === search) {
            return true;
        }
        else if (middleItem < search) {
            left = middle + 1;
        }
        else {
            right = middle - 1;
        }
    }
    return false;
}

binarySearch([2, 5, 7, 9], 7); //=> true
binarySearch([2, 5, 7, 9], 1); //=> false

متغیرهای middle و middleItem در ابتدای بدنه تابع تعریف شدن، پس در کل محدوده ایجاد شده توسط بدنه تابع در دسترس هستن. متغیر middle اندیس میانی جستجوی باینری رو نگهداری میکنه درحالیکه متغیر middleItem آیتم میانی رو نگهداری میکنه. اما این دو متغیر فقط درون بلوک while استفاده شدن؛ پس چرا این متغیرها رو مستقیما در بلوک while تعریف نکنیم؟

function binarySearch(array, search) { 
    let left = 0;
    let right = array.lengh - 1;

    while(left <= right) {
        const middle = Math.floor((left + right) / 2 );
        const middleItem = array[middle];
        if (middleItem === search) {
            return true;
        }
        else if (middleItem < search) {
            left = middle + 1;
        }
        else {
            right = middle - 1;
        }
    }
    return false;
}

حالا دو متغیر فقط در محدوده ای که از اونها استفاده میشه قرار دارن. اونها چرخه عمر و قلمرو حداقلی دارن و فهمیدن نقش اونها راحت تره.

3. تعریف نزدیک به محل استفاده

بعضی از برنامه‌نویس‌ها عادت دارن تمام متغیرها رو در بالای بدنه تابع تعریف کنن به خصوص اگه تابع بزرگ باشه. اما این کار یک جنبه منفی داره و اون هم اینکه اگه پس از مدتی به کد رجوع کنید این سوال برای شما پیش میاد: "متغیری رو میبینم که اینجا تعریف شده، ولی کجا استفاده شده؟"
فرض کنید تابعی دارید که دارای دستورات زیادی در بدنه خودش هست. شما متغیری به نام result رو در اول تابع تعریف و مقداردهی می‌‎کنید:

function myFunction(param) {
    const result = anotherFunction(param);
    let something;

    /*
        some statements...
    */

    return something + result;
}

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

function myFunction(param) {
    let something;
    
    /*
    some statements...
    */
   
    const result = anotherFunction(param);
    return something + result;
}

حالا متغیر result در جای مناسب خودش قرار داره.

4. خوانایی بهتر، نتیجه‌ی نام‌گذاری مناسب

احتمالا تابحال درباره نام‎گذاری مناسب متغیرها چیزهای زیادی شنیدید. از بین قوانین زیاد نام‌گذاری متغیرها من دو مورد مهم از اونها رو بیان میکنم.

الف) از قاعده camel-case برای نام‌گذاری متغیرها استفاده کنید:

const name = "John";

let isLoading = false;

const userAge = 21;

تنها استثنا در رابطه با قانون بالا، متغیرهایی هستن که معنای خاصی دارن و یا بسیار مهم هستن. این متغیر ها معمولا با حروف بزرگ و underline بین کلمات نام‌گذاری میشن و به این شکل از متغیرهای عادی متمایز میشن:

const APP_URL = "https://sokanacademy.com";

const SECONDS_IN_MINUTE = 6;

const ENTITY_TYPE = "blog";

const GRAPHQL_URI = "https://site.com/graphql";


ب) نام متغیر باید به وضوح نقش و داده ای که درون اون نگهداری میشه رو نشون بده.

let isLoading = true;

const message = "welcome to Sokan Academy";

let counter = 0;

همونطور که از اسم ‘isLoading’ متوجه میشیم، این متغیر یک مقدار Boolean رو نگهداری میکنه و نشون‌دهنده اینه که آیا قسمت مورد نظر در وضعیت loading هست یانه.

نام ‘message’ نشون‌دهنده اینه که این متغیر یک پیام رو نگهداری میکنه که عموما به صورت رشته string هست.

Counter هم مشخصا مربوط به یک شمارنده هست که مقادیر int رو نگهداری میکنه.
برای پی بردن به اهمیت این موضوع یک مثال میزنم. فرض کنید در حال بررسی کدهای یک برنامه هستین و با تابع زیر مواجه میشین

function salary(ws, r) {
    let t = 0;
    for(w of ws){
        t += w * r;
    }
    return t;
}

با نگاه به این تابع چه چیزی دستگیرتون میشه؟ می‌تونید بفهمید که تابع چه کاری انجام میده؟ کاری مربوط به دستمزد؟ متغیر ها به چه معنا هستن؟ متاسفانه متغیرهای ws, r, w, t هیچ اطلاعاتی درباره نقششون نمیدن.

بیاین متغیرها رو دوباره، اما این بار صحیح نام‌گذاری کنیم:

function calculateTotalSalary(weeksHours, ratePerHour) {
    let totalSalary = 0;

    for(let weekHours of weeksHours){
        const weeklySalary = weekHours * ratePerHour;
        totalSalary += weeklySalary;
    }
    return totalSalary;
}

حالا کد خیلی واضح نشون میده که کار تابع چیه و هرکدوم از متغیرها چه نقشی دارن. این قدرتِ نام‌گذاری خوبه!

5. تعریف متغیرهای میانی

یکی از کارهایی که خیلی بین برنامه‌نویس‌ها رایجه، کامنت نویسیه. اما کامنت گذاشتن های زیاد هم خودش یک روش غلطه! خوب میشد اگه کدهایی مینوشتیم که نیاز به توضیح اضافه ندارن یا به عبارت دیگه self explanatory (خود-توضیح‌دهنده) بودن. رسیدن به این هدف نیازمند نام‌گذاری مناسب متغیرها، توابع، کلاس‌ها و ویژگی‌ها هست.

یک تمرین خوب برای نوشتن کدهای self explanatory ، معرفی متغیرهای میانی هست؛ این متغیرها در زمانیکه با دستورات طولانی مواجه هستیم بسیار کمک‌کننده خواهند بود. تکه کد زیر رو در نظر بگیرید:

const sum = val1 * val2 + val3 / val4;

بیاین دوتا متغیر میانی تعریف کنیم و خوانایی کد رو بالاتر ببریم:

const multiplication = val1 * val2;
const division = val3 / val4;
const sum = multiplication + division;

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

 function binarySearch(array, search) { 
    let left = 0;
    let right = array.lengh - 1;

    while(left <= right) {
        const middle = Math.floor((left + right) / 2 );
        const middleItem = array[middle];
        if (middleItem === search) {
            return true;
        }
        else if (middleItem < search) {
            left = middle + 1;
        }
        else {
            right = middle - 1;
        }
    }
    return false;
}

در اینجا، middleItem یک متغیر میانیه که وظیفش نگهداری آیتم میانی (middle item) هست. وقتی به جای اینکه مستقیما از array[middle] استفاده کنیم، از متغیر میانی middleItem استفاده میکنیم، کار ما آسون‌تر و خوانایی کد بیشتر خواهد شد. حالا اجازه بدین نگاهی به نسخه دیگه ای از همین تابع اما بدون متغیر میانی بندازیم

function binarySearch(array, search) { 
    let left = 0;
    let right = array.lengh - 1;

    while(left <= right) {
        const middle = Math.floor((left + right) / 2 );
        if (array[middle] === search) {
            return true;
        }
        else if (array[middle] < search) {
            left = middle + 1;
        }
        else {
            right = middle - 1;
        }
    }
    return false;
}

همونطور که میبینین، خوندن و فهمیدن این نسخه بدون متغیر میانی سخت و زمان‌بر تره.

از متغیر های میانی استفاده کنید تا کد رو با خودِ کد توضیح بدین! درسته که استفاده از این نوع متغیرها کمی خطوط بیشتر به کد اضافه میکنه، اما در قبال افزایش خوانایی کد، ارزش این کار رو داره.

جمع بندی

ما همواره در حال استفاده از متغیرها هستیم و با اون ها سروکار داریم.

بیاین یه بار دیگه موارد بالا رو با هم مرور کنیم:

  • سعی کنید در زمان تعریف متغیرها همیشه استفاده از const رو به let ترجیح بدین، مگر جایی که نیاز به استفاده از let دارین.
  • قلمرو توابع رو تا حدامکان کوچک نگه دارید و بهتره که در نزدیک ترین محل استفاده تابع اون رو تعریف کنید.
  • اهمیت انتخاب نام مناسب برای متغیرها رو دست کم نگیرید و همواره این قانون رو دنبال کنید: " نام متغیر باید واضح و بدون ابهام نشان دهنده نوع داده‌ای که متغیر نگهداری میکنه باشه". از استفاده کردن از نام‌های طولانی نترسید یا به بیان دیگه، واضح بودن رو فدای کوتاه بودن نکنید.
  • به جای پر کردن کد از کامنت‌ها، سعی کنید کدی بنویسید که خودش رو توضیح بده! و هر کس با خوندن اون بتونه به هدف کد پی ببره. در شرایط پیچیده از متغیرهای میانی استفاده کنید.

 تعریف و استفاده درست و با قاعده از متغیرها کمک شایانی به افزایش خوانایی کد میکنه. شما چه best practice های دیگه ای‌ رو میدونید که باعث افزایش کیفیت  متغیرها بشه؟ برامون بنویسید.

پیشنهادات بیشتر سکان بلاگ برای شما