جدیدترین ویژگی های جاوا اسکریپت که باید بدانید + کد نمونه

ویژگی های جاوا اسکریپت

جاوا اسکریپت یا اکما اسکریپت(ECMA Script‌) یک زبان در حال تکامل است. به این معنی که هر ساله ویژگی های جدیدی به جاوا اسکریپت اضافه و نسخه جدیدی از این زبان به علاقه‌مندان ارائه می‌شود. TC39 یا کمیته فنی ۳۹‌، کمیته‌ی مسئول تعریف استانداردهای جدید جاوا اسکریپت می‌باشد. خبر خوش اینکه این کمیته امسال بسیار فعال بوده‌است و عناوین زیادی به ویژگی های جاوا اسکریپت اضافه کرده‌است.

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

جاوا اسکریپت دست به شخصی‌سازی زد!

درست شنیدید. بالاخره جاوا اسکریپت هم برای رعایت حریم‌شخص property ها و method ها(!) تصمیم گرفت تا امکان ایجاد دسترسی private‌ را در class‌ها راه اندازی کند.

// private fields must start with '#'
// and they can't be accessed outside the class block

class Counter {
  #x = 0;

  #increment() {
    this.#x++;
  }

  onClick() {
    this.#increment();
  }

}

const c = new Counter();
c.onClick(); // works fine
c.#increment(); // error

برای اطلاعات بیشتر و دیدن مثال‌های بیشتر میتونید به این اکانت گیت‌هاب مراجعه کنید.

Optional Chaining

آپشن جدید که به ویژگی های زبان جاوا اسکریپت اضافه شده است، این امکان را به ما میدهد تا هر property‌ای از هر object ای که میخواهیم را فراخوانی کنیم، بدون اینکه نگران منفجر شدن برنامه باشیم!

دوره های اموزشی برنامه نویسی
var lang = {
    en: "English",
    es: "Español",
    fr: "Français"
}
console.log(lang.fa.words) // Throw exception error and your app has blown up

کد بالا را در نظر بگیرید. برای اینکه برنامه به مشکل نخورد باید با متدهای typeof یا hasOwnProperty قبل از استفاده، چک کنیم که words در fa وجود دارد یا نه.

اما با کمک آپشن جدیدی که جاوا اسکریپت در اختیار ما قرار داده است فراخوانی یک operator برای هندل کردن مقادیر undefined یا null کافی است(بدون انفجار برنامه!)

console.log(lang?.fa?.words) 
// undefined but everything else is ok

در نتیجه کد بالا، در خروجی TypeError: Cannot read property ‘fa’ را نمیبینیم و فقط undefined یا null را برمیگرداند.

این آپشن در ساختار شرطی if هم به کار می‌آید:

if(lang?.en?.words){
    // Do something 
}else{
    // Do another thing
}

قدرت واقعی این ویژگی زمانی خودنمایی می‌کند که با object های بزرگ و پیچیده سروکار داریم:

console.log(lang?.en?.words?.rudeWords?.['a bad word'])

به طور خلاصه optional chaining وجود گره یا نود میانی در درخت(مثل object های چند لایه) را چک میکند و از بروز خطا در صورت عدم وجود نود میانی، جلوگیری می‌کند.

Nullish Coalescing

ویژگی های جاوا اسکریپت

حین برنامه‌نویسی بارها پیش می‌آید که مجبور میشوید یک مقدار default برای متغییر خود در نظر بگیرید. تا به اینجا همه‌چیز خوب است اما با کمی اغراق در همه مشکلات پای Daynamic Type در میان است!

var validNumber = 0;
var nullValue = null; /* Null or undefined will be ignored/false with this operator  */

console.log(validNumber || 42);
// ۴۲

کد بالا را در نظر بگیرید. هدف ما از نوشتن این کد این است که اگر مقداری برای متغییر validNumber وجود نداشت، مقدار default 42 را چاپ کنیم. مشکل کجاست؟ ما انتظار داریم صفر را چاپ کند چون validNumber مقدار دارد و مقدار آن برابر است با صفر.

اما اتفاقی که میوفتد این است که جاوا اسکریپت یک تبدیل type‌ داینامیک انجام می‌دهد و صفر را معادل null در نظر میگیرد. پس با این حساب از نظر جاوا اسکریپت validNumber مقدار ندارد و مقدار دیفالت را در خروجی چاپ می‌کند.

شاه کلید این مشکل اینجاست:

var validNumber = 0;
var nullValue = null; /* Null or undefined will be ignored/false with this operator  */

console.log(validNumber ?? 42);
// ۰

console.log(nullValue ?? 7);
// ۷

همانطور که می‌بینید این شاه‌کلید از جعل type‌ها جلوگیری میکند.

Top-level await

قبل از اینکه به توضیح این مطلب بپردازم لازم میدونم نکته‌ای را مرور کنم. زبان جاوا اسکریپت در ذات sync  است، یعنی چی؟ فرض کنید چند تابع به زبان جاوا اسکریپت نوشته‌ایم، تمام این توابع با هم اجرا میشوند. حالا فرض کنید در برنامه‌ای ۲ تابع داریم که تابع اول خروجی a را تولید میکند و باید این خروجی را به عنوان پارامتر به تابع دوم ارسال کنیم.

طبق خاصیت همزمانی در جاوا اسکریپت، برنامه ما احتمالا به مشکل میخورد( در شرایط واقعی زمان اجرای هر تابع ملاک است). در واقع ممکن است هنوز خروجی a تولید نشده باشد و تابع دوم فراخوانی شود!

برای جلوگیری از همچین مشکلاتی، await و async در جاوا اسکریپت تعریف شده است تا امکان ایجاد کدهای غیر همزمان را برای ما فراهم کنند. با قرار دادن async قبل از تعریف تابع، آن تابع را غیرهمزمان تعریف می‌کنیم. از طرفی با قرار دادن await قبل از هر خط کد داخل تابع که باید مکث کند، این غیر همزمانی را ایجاد می‌کنیم.(پیشرفته promise ها)

حالا به سراغ await سطح بالا میرویم: Top-level await به ماژول‌ها این امکان رو میدن که مثل یک تابع غیر همزمان بزرگ عمل کنند! به عبارتی بحث ایجاد غیرهمزمانی را روی ماژول‌ها اعمال می‌کنند.

// db.mjs
export const connection = await createConnection();
// server.mjs
import { connection } from './db.mjs';

server.start();

در کد بالا مادامیکه connection در ماژول db.mjs تکمیل نشده است، هیچ کدی در ماژول server.mjs اجرا نمی‌شود.

Dynamic import

ویژگی های جدید جاوا اسکریپت- Dynamic import

این ویژگی جدید به فایل جاوا اسکریپت این امکان را میدهد تا هر زمان که نیاز داشت، ماژول مورد نظر را لود کند.

تا قبل از این وقتی ماژول‌هایی را در فایل جاوا اسکریپت import می‌کردیم، فایل‌ها قبل از زمان اجرا (pre-runtime) لود میشدند، به همین دلیل تمام ماژول‌ها را ابتدای فایل import می‌کنیم.

روش فعلی مشکلی ندارد اما اگر بتوانیم با کمک داینامیک import و برای افزایش راندمان بهتر است بعضی از ماژول‌ها را در زمان اجرا(runtime) لود کنیم.

const main = document.querySelector("main");
  for (const link of document.querySelectorAll("nav > a")) {
    link.addEventListener("click", e => {
      e.preventDefault();

      import(`./section-modules/${link.dataset.entryModule}.js`)
        .then(module => {
          module.loadPageInto(main);
        })
        .catch(err => {
          main.textContent = err.message;
        });
    });
  }

Dynamic import به دولوپرها این امکان را میدهد که کنترل بیشتری روی نحوه لود ماژول‌ها در application‌ داشته باشند.

() Object.fromEntries

تبدیل آرایه به object و برعکس آن، یک نیاز رایج است. مخصوصا اگر با پایگاه داده‌های no-sql کار کرده باشید بارها و بارها به این نوع تبدیل‌ها نیاز پیدا کرده‌اید. در سال ۲۰۱۷ object.entries() برای تبدیل شی به آرایه معرفی شد.

const object1 = {
  foo: "somestring",
  bar: 100
};

for (let [key, value] of Object.entries(object1)) {
  console.log(`${key}: ${value}`);
}

// Outputs-->
// foo: somestring 
// bar: 100 

Object.fromEntries() برعکس object.entries() عمل می‌کند. به عبارتی آرایه را می‌گیرد و به عنوان خروجی شی برمیگرداند.

const entries = new Map([
 ['foo', 'bar'],
 ['baz', 42]
]);

const obj = Object.fromEntries(entries);

console.log(obj);
// expected output: Object { foo: "bar", baz: 42 }

() String.prototype.matchAll

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

const re = /(Dr\. )\w+/g;
const str = 'Dr. Smith and Dr. Anderson';
const matches = str.matchAll(re);

for (const match of matches) {
  console.log(match);
}

// outputs:
// => ["Dr. Smith", "Dr. ", index: 0, input: "Dr. Smith and Dr. Anderson", groups: undefined]
// => ["Dr. Anderson", "Dr. ", index: 14, input: "Dr. Smith and Dr. Anderson", groups: undefined]

این متد کار با رشته‌ها، زیر رشته‌ها و الگوها را آسان می‌کند. البته با کمک regex(regular expersion)

WeakRef

WeakRef یا اشاره ضعیف به یک شی برای زنده‌نگهداشتن آن شی کافی نیست! وقتی شما با const, let یا var یک متغیر ایجاد می‌کنید، garbeg collector‌ مادامیکه شما اشاره به آن متغیر را حذف نکنید، آن را از حافظه حذف نمیکند. اما اگر شما یک اشاره ضعیف به شی داشته باشید، ممکن است gc آن شی را از حافظه حذف کند. WeakRef یک متد دارد به اسم deref‌ که اشاره اصلی به شی را برمیگرداند.

WeakRef زمانی میتواند مفید واقع شود که شما میخواهید شی‌های کم‌ارزش را در حافظه cach قرار دهید و نمیخواهید آن‌ها در حافظه اصلی باشند.

const cache = new Map();

const setValue =  (key, obj) => {
  cache.set(key, new WeakRef(obj));
};

const getValue = (key) => {
  const ref = cache.get(key);
  if (ref) {
    return ref.deref();
  }
};

// this will look for the value in the cache
// and recalculate if it's missing
const fibonacciCached = (number) => {
  const cached = getValue(number);
  if (cached) return cached;
  const sum = calculateFibonacci(number);
  setValue(number, sum);
  return sum;
};

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

اگر در این باره سوال یا تجربه‌ای دارید، خوشحال میشم با ما و سایر خوانندگان چ‌ یاب مطرح کنید.

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

برای اطلاع از آخرین اخبار و آموزش‌های ما می‌تونید در کانال تلگرام ‌چ‌ یاب عضو شید.

منابع:

مهندس کامپیوتر👩‍💻 | علاقه‌مند به برنامه نویسی💻| دیجیتال مارکتینگ📱| بسکتبال🏀| تولید محتوا🖋