9 حقه برای توسعه‌دهندگان JavaScript حرفه‌ای در سال 2019

یک سال دیگر به اتمام رسید و JavaScript همیشه در حال تغییر است. گرچه، برخی نکات وجود دارند که می‌توانند به شما کمک کنند تا کد مرتب و موثری بنویسید که حتی در سال ۲۰۱۹ هم مقیاس‌پذیر است. در اینجا ۹ نکته عملگرا را مشاهده می‌نمایید که شما را تبدیل به یک توسعه دهنده بهتر می‌نمایند.

۱. async / await

اگر هنوز در callback hell گیر کرده‌اید، سال ۲۰۱۴ کد خود را پس می‌گیرد. تا زمانی که callbackها کاملا ضروری نیستند، از آن‌ها استفاده نکنید. مثلا وقتی که برای یک کتابخانه و به علل مربوط به کارایی، مورد نیاز هستند. Promiseها خوب هستند، اما اگر سورس کد شما بزرگ شود، استفاده از آن‌ها کمی ضایع است. امروزه راه حل اول من async / await می‌باشد که خواندن و بهبود بخشیدن به کد من را بسیار راحت‌تر می‌کند. در واقع، شما می‌توانید هر Promiseای را در جاوااسکریپت await کنید. در صورتی که کتابخانه مورد استفاده شما یک promise را بر می‌گرداند، به سادگی آن را await کنید. در واقع، async / await در موقعیت مربوط به یک promise بسیار ساده است. برای این که کد خود را وادار به کار کنید، باید کلمه کلیدی async‌ را جلوی تابع اضافه کنید. در اینجا یک مثال کوتاه را مشاهده می‌نمایید:

async function getData() {

    const result = await axios.get('https://dube.io/service/ping')

    const data = result.data

    console.log('data', data)

   
    return data

}

getData()

دقت کنید که await در سطح بالا ممکن نیست؛ شما فقط می‌توانید یک تابع async را فراخوانی کنید.

async / await به همراه ES۲۰۱۷ معرفی شد؛ پس مطمئن شوید که کد خود را transpile می‌کنید.

۲. جریان کنترل async

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

for...of

فرض کنید که ما چند سریال تلویزیونی بر روی صفحه خود داریم، و باید اطلاعاتی را به همراه جزئیات درباره آن‌ها به دست بیاوریم. ما نمی‌خواهیم منتظر تمام فراخوانی‌ها بمانیم تا به پایان برسند، به خصوص وقتی که نمی‌دانیم چند فراخوانی داریم؛ اما ما می‌خواهیم دیتاست خود را به محض این که چیزی را در جواب دریافت کردیم، بروزرسانی کنیم. ما می‌توانیم از حلقه for…of بر روی یک آرایه استفاده کنیم و کد async داخل بلوک را اجرا کنیم. این اجرا تا زمانی که هر فراخوانی با موفقیت انجام شده است، متوقف خواهد شد. مهم است دقت کنید که اگر کاری به مانند این را در کد خود انجام دهید، ممکن است با برخی تنگناهای کارایی مواجه شوید، اما داشتن آن در میان مجموعه ابزار خود، کاربردی است. برای مثال:

import axios from 'axios'

let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}]

async function fetchData(dataSet) {
    for(entry of dataSet) {
        const result = await axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`)
        const newData = result.data
        updateData(newData)
        
        console.log(myData)
    }
}

function updateData(newData) {
    myData = myData.map(el => {
        if(el.id === newData.id) return newData
        return el
    })
}
    
fetchData(myData)

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

Promise.all

اگر بخواهیم تمام سریال‌ها را به موازات هم دریافت کنید چه؟ از آنجایی که می‌توانید تمام promiseها را await کنید، به سادگی از Promise.all استفاده کنید:

import axios from 'axios' 

let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}]

async function fetchData(dataSet) {
    const pokemonPromises = dataSet.map(entry => {
        return axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`)
    })

    const results = await Promise.all(pokemonPromises)
    
    results.forEach(result => {
        updateData(result.data)
    })
    
    console.log(myData) 
}

function updateData(newData) {
    myData = myData.map(el => {
        if(el.id === newData.id) return newData
        return el
    })
}
    
fetchData(myData)

For…of و promise.all در ES۶+ معرفی شدند؛ پس مطمئن شوید که کد خود را transpile می‌کنید.

۳. تخریب (destructuring) و مقادیر پیشفرض

بیایید به مثال‌های قبلی خود باز گردیم، که در آن‌ها این کار را انجام می‌دهیم:

const result = axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`)

const data = result.data

یک راه ساده‌تر برای انجام این کار وجود دارد. ما می‌توانیم از تخریب استفاده کنیم، تا یک یا چند مقدار را از یک آبجکت یا یک آرایه بگیریم. ما فقط باید چنین کاری را انجام دهیم:

const { data } = await axios.get(...)

ما یک خط کد کمتر نوشتیم. شما همچنین می‌توانید متغیر خود را مجددا نامگذاری کنید:

const { data: newData } = await axios.get(...)

یک حقه قشنگ دیگر این است که در هنگام تخریب، مقادیر پیشفرض را بدهید. این کار تضمین می‌کند که شما هیچ وقت با یک خطای undefined مواجه نخواهید شد و مجبور نخواهید بود که متغیرها را به صورت دستی بررسی کنید.

const { id = 5 } = {}

console.log(id) // 5

این حقه‌ها هم می‌توانند به همراه پارامترهای تابع استفاده شوند. برای مثال:

function calculate({operands = [1, 2], type = 'addition'} = {}) {
    return operands.reduce((acc, val) => {
        switch(type) {
            case 'addition':
                return acc + val
            case 'subtraction':
                return acc - val
            case 'multiplication':
                return acc * val
            case 'division':
                return acc / val
        }
    }, ['addition', 'subtraction'].includes(type) ? 0 : 1)
}

console.log(calculate()) // 3
console.log(calculate({type: 'division'})) // 0.5
console.log(calculate({operands: [2, 3, 4], type: 'multiplication'})) // 24

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

تخریب در ES۶ معرفی شد؛ پس مطمئن شوید که کد خود را transpile می‌کنید.

۴. مقادیر truthy و falsy

وقتی که از مقادیر پیشفرض استفاده می‌کنید، برخی از بررسی کردن‌ها برای مقادیر موجود، مربوط به گذشته خواهند بود. گرچه، خوب است بدانید که می‌توانید با مقادیر truthy و falsy‌ کار کنید. این کار کد شما را بهبود خواهد بخشید و شما را از انجام برخی دستور العمل‌‌ها نجات خواهد داد، که در نتیجه کد شما شیوا خواهد شد. من اغلب می‌بینم که مردم چنین کاری انجام می‌دهند:

if(myBool === true) {
  console.log(...)
}
// OR
if(myString.length > 0) {
  console.log(...)
}
// OR
if(isNaN(myNumber)) {
  console.log(...)
}

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

if(myBool) {
  console.log(...)
}
// OR
if(myString) {
  console.log(...)
}
// OR
if(!myNumber) {
  console.log(...)
}

برای این که واقعا از این بیانیه‌ها بهره ببرید، باید درک کنید که مقادیر truthy‌ و falsy چه هستند. در اینجا یک بازبینی کوچک را درباره آن‌ها مشاهده می‌نمایید:

Falsy

  • رشته‌هایی با طول صفر
  • عدد صفر
  • False
  • Undefined
  • Null (خالی)
  • NaN (Not a number = غیر عدد)

Truthy

  • آرایه‌های خالی
  • آبجکت‌های خالی
  • هر چیز دیگری

دقت کنید که وقتی مقادیر truthy / falsy‌ را بررسی می‌کنید، هیچ مقایسه صریحی در آن‌ها وجود ندارد، که این برابر است با بررسی با استفاده از علامت دو مساوی (==)، نه این که سه مورد از آن‌ها را به کار ببرید (===). عموما این علامت هم رفتار مشابهی به مانند مورد اول دارد، اما برخی موقعیت‌های خاص وجود دارند که شما در نهایت با یک باگ مواجه خواهید شد. برای من، این اتفاق بیشتر با عدد صفر می‌افتاد.

9 حقه برای توسعه‌دهندگان JavaScript حرفه‌ای در سال 2019

۵. عملگرهای منطقی و سه‌گانه

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

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

عملگرهای منطقی اساسا دو عبارت را ترکیب می‌کنند و true، false یا مقادیری که توسط && یا || نمایش داده شده‌اند را بر می‌گردانند. بیایید نگاهی به آن‌ها داشته باشیم:

console.log(true && true) // true
console.log(false && true) // false
console.log(true && false) // false
console.log(false && false) // false
console.log(true || true) // true
console.log(true || false) // true
console.log(false || true) // true
console.log(false || false) // false

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

  • &&: مقادیر falsy برگردانده می‌شوند. اگر هیچ مقدار falsyای وجود نداشته باشد، آخرین مقدار truthy برگردانده می‌شود.
  • ||: اولین مقدار truthy برگردانده می‌شود. اگر هیچ مقدار truthyای وجود نداشته باشد، عملیات برابر با پنج مقدار falsy آخر خواهد بود.
console.log(0 && {a: 1}) // 0
console.log(false && 'a') // false
console.log('2' && 5) // 5
console.log([] || false) // []
console.log(NaN || null) // null
console.log(true || 'a') // true

عملگرهای سه‌گانه

عملگر سه‌گانه، بسیار مشابه به عملگرهای منطقی است، اما سه بخش دارد:

۱. مقایسه، که نتیجه‌اش یا falsy و یا truthy خواهد بود.

۲. اولین مقدار برگشتی، در صورتی که نتیجه مقایسه truthy‌ باشد.

۳. دومین مقدار برگشتی، در صورتی که نتیجه مقایسه falsy باشد.

در اینجا یک مثال را مشاهده می‌نمایید:

const lang = 'German'
console.log(lang === 'German' ? 'Hallo' : 'Hello') // Hallo
console.log(lang ? 'Ja' : 'Yes') // Ja
console.log(lang === 'French' ? 'Bon soir' : 'Good evening') // Good evening

۶. زنجیره کردن اختیاری

آیا تا به حال مشکل دسترسی به یک ویژگی آبجکت تو در تو را بدون این که بدانید اگر آبجکت مورد نظر، یا یکی از ویژگی‌های زیر مجموعه آن اصلا وجود دارد یا نه داشته‌اید؟ احتمالا در نهایت به چیزی به مانند این مورد خواهید رسید:

let data
if(myObj && myObj.firstProp && myObj.firstProp.secondProp && myObj.firstProp.secondProp.actualData) data = myObj.firstProp.secondProp.actualData

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

const data = myObj?.firstProp?.secondProp?.actualData

من فکر می‌کنم که این یک راه ظریف برای بررسی ویژگی‌های تو در تو بوده، و کد ما را بسیار مرتب‌تر می‌کند.

۷. ویژگی‌های کلاس و binding

Bind‌ کردن توابع در JavaScript، یک عملیات رایج است. با معرفی توابع پیکانی در مشخصه ES۶، حال ما راهی داریم تا توابع را به صورت خودکار به زمینه تعریف خود bind کنیم. این روش بسیار کاربردی بوده، و در میان توسعه‌دهندگان JavaScript به طور رایج استفاده می‌شود. وقتی که کلاس‌ها در ابتدا معرفی شده بودند، دیگر نمی‌توانستید از توابع پیکانی استفاده کنید؛ زیرا متدهای کلاس باید به روشی مشخص تعریف شوند. ما مجبور بودیم که توابع را در جای دیگری bind کنیم؛ برای مثال در constructor. من همیشه توسط جریان کاری اولین متد کلاس تعریف کننده و سپس bind کردن آن‌ها اذیت می‌شدم. این کار پس از مدتی مسخره به نظر می‌آمد. با سینتکس ویژگی کلاس، ما می‌توانیم باز هم از توابع پیکانی استفاده کنیم و از bind خودکار بهره ببریم. حال توابع پیکانی می‌توانند داخل کلاس استفاده شوند. در اینجا مثالی با _increaseCount را در هنگام bind شدن می‌بینید:

class Counter extends React.Component {
    constructor(props) {
        super(props)
        this.state = { count: 0 }
    }
    
    render() {
        return(
            <div>
                <h1>{this.state.count}</h1>  
                <button onClick={this._increaseCount}>Increase Count</button>
            </div>
        )
    }
    
    _increaseCount = () => {
        this.setState({ count: this.state.count + 1 })
    }
}

۸. از parcel استفاده کنید

شما به عنوان یک توسعه دهنده frontend، احتمالا با کد bundle‌ کردن و transpile‌ کردن مواجه شده‌اید. استاندارد بالفعل برای این کار، برای مدت زیادی Webpack بود. من در ابتدا از Webpack‌ نسخه ۱ استفاده کردم، یک در آن زمان یک عذاب بزرگ بود. من با بازی کردن با گزینه‌های پیکربندی مختلف، ساعات بی شماری را صرف تلاش برای bundle‌ کردن و شروع به کار کردم. اگر می‌توانستم، دیگر به آن دست نمی‌زدم تا چیزی را خراب نکنم. یکی دو ماه پیش به Parcel بر خوردم، که یک تسکین فوری برای من بود. این ابزار تقریبا هر کاری را برای شما انجام می‌دهد، درحالیکه همچنان قابلیت تغییر آن را در صورت لزوم به شما می‌دهد. Parcel همچنین از یک سیستم پلاگین، مشابه به Webpack‌ یا Babel پشتیبانی می‌کند و به شدت سریع است. اگر Parcel را نمی‌شناسید، پیشنهاد می‌کنم که حتما به آن نگاهی داشته باشید.

۹. خودتان کد بیشتری بنویسید

این یک موضوع جالب است. من مباحث زیادی درباره آن داشته‌‌ام. حتی برای CSS هم افراد زیادی می‌خواهند از یک کتابخانه کامپوننت مانند Bootstrap استفاده کنند. برای JavaScript، من همچنان افرادی را می‌بینم که از jQuery و کتابخانه‌های کوچک برای اعتبارسنجی، sliderها و... استفاده می‌کنند. با این که استفاده از یک کتابخانه عقلانی است، اما من به شدت پیشنهاد می‌کنم که به جای نصب پکیج‌های npm، خودتان کد بیشتری بنویسد. وقتی که کتابخانه‌های (یا حتی فریم‌وورک‌های) بزرگی مانند moment.js یا react-datepicker وجود دارند، که یک تیم کامل در حال ساخت آن‌ها است، نوشتن کد توسط خودتان عقلانی نیست. گرچه، شما می‌توانید اکثر کدی که از آن استفاده می‌کنید را خودتان بنویسید. این کار، سه برتری اصلی به شما خواهد داد:

۱. شما دقیقا می‌دانید که چه اتفاقی در کدتان می‌افتد.

۲. بالاخره در جایی شروع به درک واقعی برنامه‌نویسی و نحوه کار همه چیز خواهید کرد.

۳. می‌توانید از پف کردن سورس کد خود جلوگیری کنید.

در ابتدای راه، استفاده از یک پکیج npm‌ ساده‌تر است. پیاده‌سازی عملکردها توسط خودتان، زمان بیشتری خواهد برد. اما اگر پکیج مورد نظر طبق انتظار کار نکند و مجبور باشید آن را با یک پکیج دیگر عوض کنید، و زمان بیشتری را صرف نحوه راه‌اندازی API‌ آن‌ها کنید چه؟ وقتی که خودتان یک پکیج را پیاده‌سازی می‌کنید، می‌توانید آن را صد درصد با نیازهای خود تطبیق دهید.

منبع