12 مفهوم جاوااسکریپت که باعث افزایش مهارت‌های توسعه شما می‌شود

چهارشنبه 8 مرداد 1399

جاوااسکریپت یک زبان پیچیده است. اگر توسعه‌دهنده جاوااسکریپت در هر سطحی هستید، درک مفاهیم بنیادی آن مهم است. این مقاله به 12 مفهوم می‌پردازد که درک آن برای هر توسعه‌دهنده JS ای مهم است، اما به هیچ وجه بیانگر وسعت کامل آنچه که توسعه‌دهنده JS باید بداند نیست.

12 مفهوم جاوااسکریپت که باعث افزایش مهارت‌های توسعه شما می‌شود

1. اختصاص دادن متغیر با مقدار در مقایسه با رفرنس

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

جاوااسکریپت همیشه متغیرها را بر اساس مقدار اختصاص می‌دهد. اما این بخش بسیار مهم است: وقتی مقدار اختصاصی یکی از پنج نوع اصلی جاوااسکریپت باشد (یعنی Boolean، null، undefined، String و Number) مقدار واقعی اختصاص داده می‌شود. با این حال، وقتی مقدار اختصاصی یک آرایه، تابع، یا آبجکت است، رفرنسی به آبجکت در حافظه اختصاص داده می‌شود.

مثال؛ در کد زیر var2 برابر است با var1. از آنجا که var1 نوع اصلی است (Stringvar2 با مقدار رشته‌ای var1 ست شده است و می‌توان تصور کرد که در این مرحله کاملا متمایز از var1 است. بر این اساس، اختصاص مجدد var2 تاثیری بر var1 ندارد.

let var1 = 'My string';
let var2 = var1;var2 = 'My new string';console.log(var1);
// 'My string'
console.log(var2);
// 'My new string'

بیایید این را با اختصاص آبجکت مقایسه کنیم

let var1 = { name: 'Jim' }
let var2 = var1;var2.name = 'John';console.log(var1);
// { name: 'John' }
console.log(var2);
// { name: 'John' }

ممکن است ببینید اگر انتظار دارید رفتاری مثل اختصاص متغیرهای اصلی داشته باشد، چگونه می‌تواند مشکلاتی ایجاد کند! این عمل به ویژه وقتی که تابعی ایجاد کنید که ناخواسته یک آبجکت را تغییر دهد، می‌تواند بد باشد.

2. Closures

Closures یک الگوی مهم جاوااسکریپت برای دسترسی خصوصی (private) به یک متغیر است. در این مثال، createGreeter یک anonymous function را برمی‌گرداند که به greeting دسترسی دارد، " Hello". برای همه استفاده‌های آتی، sayHello به این greeting دسترسی خواهد داشت!

function createGreeter(greeting) {
  return function(name) {
    console.log(greeting + ', ' + name);
  }
}const sayHello = createGreeter('Hello');
sayHello('Joe');
// Hello, Joe

در یک سناریوی واقعی‌تر، یک تابع اولیه apiConnect(apiKey) را در نظر بگیرید که برخی متدهایی را که از API key استفاده می‌کنند را برمی‌گرداند. در این حالت، apiKey نیاز دارد که فقط یک بار آماده شود و دیگر نیازی نیست دوباره انجام شود.

function apiConnect(apiKey) {
  function get(route) {
    return fetch(`${route}?key=${apiKey}`);
  }  function post(route, params) {
    return fetch(route, {
      method: 'POST',
      body: JSON.stringify(params),
        headers: {
          'Authorization': `Bearer ${apiKey}`
        }
      })
  }  return { get, post }
}const api = apiConnect('my-secret-key');// No need to include the apiKey anymore
api.get('http://www.example.com/get-endpoint');
api.post('http://www.example.com/post-endpoint', { name: 'Joe' });

3. Destructuring

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

const obj = {
  name: 'Joe',
  food: 'cake'
}const { name, food } = obj;console.log(name, food);
// 'Joe' 'cake'

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

const obj = {
  name: 'Joe',
  food: 'cake'
}const { name: myName, food: myFood } = obj;console.log(myName, myFood);
// 'Joe' 'cake'

در مثال زیر، از این روش برای ارسال آبجکت person به تابع introduce استفاده می‌شود. به عبارت دیگر، این روش می‌تواند به صورت مستقیم برای ارسال پارامتر‌های استخراج‌شده به یک تابع استفاده شود. اگر با React آشنا باشید، احتمالا قبلا آن را دیده‌اید!

const person = {
  name: 'Eddie',
  age: 24
}function introduce({ name, age }) {
  console.log(`I'm ${name} and I'm ${age} years old!`);
}console.log(introduce(person));
// "I'm Eddie and I'm 24 years old!"

4. سینتکسSpread

عملگرspread  مفهومی در جاوااسکریپت است که نسبتا ساده است. در مثال زیر، Math.max نمی‌تواند برای آرایه arr اعمال شود، زیرا به عنوان آرگومان نمی‌تواند آرایه بگیرد، این متد عناصر منحصربه‌فرد را به عنوان آرایه می‌گیرد. عمگر spread (...) برای گرفتن عناصر منحصربه‌فرد آرایه استفاده می‌شود.

const arr = [4, 6, -1, 3, 10, 4];
const max = Math.max(...arr);
console.log(max);
// 10

5. سینتکس Rest

بیایید در مورد سینتکس rest جاوااسکریپت صحبت کنیم. می‌توانید از آن برای گذاشتن هر تعداد آرگومان ارسال‌شده به تابع در یک آرایه استفاده کنید.

function myFunc(...args) {
  console.log(args[0] + args[1]);
}myFunc(1, 2, 3, 4);
// 3

6. متدهای آرایه

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

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

1. map, filter, reduce

در رابطه با متدهای آرایه جاوااسکریپت map، filter، reduce یک سری سردرگمی وجود دارد. متدهای سودمندی برای تبدیل آرایه یا بازگرداندن یک مقدار در کنار هم وجود دارد.

map: آرایه‌ای را برمی‌گرداند که هر عنصر به عنوان مورد مشخص شده توسط تابع تبدیل شده است.

const arr = [1, 2, 3, 4, 5, 6];
const mapped = arr.map(el => el + 20);console.log(mapped);
// [21, 22, 23, 24, 25, 26]

filter: آرایه‌ای از عناصر را برمی‌گرداند که تابع true را برگرداند.

const arr = [1, 2, 3, 4, 5, 6];
const filtered = arr.filter(el => el === 2 || el === 4);console.log(filtered);
// [2, 4]

Reduce: مقادیر را به عنوان چیزی که در تابع مشخص شده است با هم جمع‌آوری می‌کند.

const arr = [1, 2, 3, 4, 5, 6];
const reduced = arr.reduce((total, current) => total + current);console.log(reduced);
// 21

7. Generatorها

از * نترسید. تابع generator مشخص می‌کند دفعه بعد که next() فراخوانی می‌شود، کدام مقدار yield است. می‌توان تعداد محدودی yield داشت، بعد از اینکه next() مقدار undefined را برمی‌گرداند، یا یک مقدار نامحدود ازمقادیر را با استفاده از حلقه برمی‌گرداند.

function* greeter() {
  yield 'Hi';
  yield 'How are you?';
  yield 'Bye';
}const greet = greeter();console.log(greet.next().value);
// 'Hi'
console.log(greet.next().value);
// 'How are you?'
console.log(greet.next().value);
// 'Bye'
console.log(greet.next().value);
// undefined

و استفاده از generator برای مقادیر نامحدود:

function* idCreator() {
  let i = 0;
  while (true)
    yield i++;
}const ids = idCreator();console.log(ids.next().value);
// 0
console.log(ids.next().value);
// 1
console.log(ids.next().value);
// 2
// etc...

8. عملگر شناسایی (===) در مقایسه با عملگر برابری (==)

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

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

9. مقایسه آبجکت

اشتباهی که بیشتر مواقع تازه‌واردها انجام می‌دهند، مقایسه مستقیم آبجکت‌ها است. متغیرها اشاره به رفرنس‌های آبجکت‌های موجود در حافظه دارند، نه خود آبجکت‌ها. یک روش برای مقایسه آن‌ها، تبدیل آبجکت‌ها به رشته‌های JSON است. این کار یک اشکال دارد: ترتیب پراپرتی آبجکت تضمین نمی‌شود. یک راه ایمن‌تر برای مقایسه آبجکت‌ها استفاده از کتابخانه‌ای است که در مقایسه عمیق آبجکت (deep comparison) تخصص دارد، مثل isEqual.

به نظر می‌رسد که آبجکت‌های زیر با هم برابر هستند اما به رفرنس‌های مختلفی اشاره می‌کنند.

const joe1 = { name: 'Joe' };
const joe2 = { name: 'Joe' };console.log(joe1 === joe2);
// false

در عوض، کد زیر درست ارزیابی می‌شود زیرا یک آبجکت برابر است با آبجکت دیگر و بنابراین به همان رفرنس اشاره می‌کند (فقط یک آبجکت در حافظه وجود دارد).

const joe1 = { name: 'Joe' };
const joe2 = joe1;
console.log(joe1 === joe2);
// true

حتما بخش مقایسه مقدار با رفرنس را در بالا بخوانید تا کاملا تنظیم متغیری که با متغیر دیگری برابر است که به یک آبجکت در حافظه اشاره دارند را درک کنید.

10. توابع Callback

افراد زیادی از توابع callback جاوااسکریپت وحشت دارند! اما آن‌ها ساده هستند. یک مثال بزنیم. تابع console.log به عنوان یک callback به myFunc ارسال می‌شود. وقتی setTimeout کامل شد، اجرا می‌شود. این همه چیزی است که وجود دارد!

function myFunc(text, callback) {
  setTimeout(function() {
    callback(text);
  }, 2000);
}myFunc('Hello wor

11. Promiseها

بعد از اینکه callbackهای جاوااسکریپت را درک کردید، به زودی خود را در callbackهای تو در تو می‌یابید. این جایی است که Promiseها به کمک شما می‌آیند. منطق async خود را در یک Promise قرار دهید و موفقیت، رد شدن یا شکست را resolve کنید. از " then" برای مدیریت موفقیت (success) و catch برای مدیریت شکست (failure) استفاده کنید.

const myPromise = new Promise(function(res, rej) {
  setTimeout(function(){
    if (Math.random() < 0.9) {
      return res('Hooray!');
    }
    return rej('Oh no!');
  }, 1000);
});myPromise
  .then(function(data) {
    console.log('Success: ' + data);
   })
   .catch(function(err) {
    console.log('Error: ' + err);
   });
   
// If Math.random() returns less than 0.9 the following is logged:
// "Success: Hooray!"
// If Math.random() returns 0.9 or greater the following is logged:
// "Error: On no!"

12. Async Await

هنگامی که به promiseهای جاوااسکریپت رسیدید، ممکن است async await را بخواهید. در مثال زیر، یک تابع async ایجاد می‌کنیم و درون آن greeter promise را await می‌کنیم.

const greeter = new Promise((res, rej) => {
  setTimeout(() => res('Hello world!'), 2000);
})async function myFunc() {
  const greeting = await greeter;
  console.log(greeting);
}myFunc();
// 'Hello world!'

جمع‌بندی

اگر هیچ کدام از این 12 مفهوم را نمی‌دانید، احتمالا حداقل کمی دانش جاوااسکریپت شما رشد کرده است و دیدی در مورد هر کدام یافته‌اید. و اگر همه آن‌ها را می‌شناسید، امیدوارم که این فرصتی برای تمرین و رشد دانش شما باشد. موفق باشید!

ایمان مدائنی

نویسنده 1299 مقاله در برنامه نویسان

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

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید