برنامه نویسی ۲۸۵ بازدید

در این مقاله می‌خواهیم برخی از قابلیت های جدید جاوا اسکریپت ES2020 یا ES11 را بررسی کنیم که فهرست آن به شرح زیر است:

  • متغیرهای خصوصی کلاس
  • متد Promise.allSettled
  • متد String.prototype.matchAll
  • عملگر زنجیره‌سازی بهینه
  • ایمپورت دینامیک
  • نوع داده BigInt

توجه کنید که همه این قابلیت‌ها روی کروم نسخه 79 تست شده‌اند.

متغیرهای خصوصی کلاس

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

class Person {
  #born = 1980
  age() { console.log(2020 - this.#born) }
}
const person1 = new Person()
person1.age() // 40
console.log(person1.#born)
//Uncaught SyntaxError: Private field '#born' must be declared in an     
//enclosing class

متد Promise.allSettled

از زمان معرفی Promise-ها در ES6، جاوا اسکریپت از دو ترکیب‌کننده Promise یعنی متدهای استاتیک Promise.all و Promise.race پشتیبانی می‌کند. اکنون Promise.allSettled نیز به ES2020 اضافه شده است.

برخلاف Promise.all یا Promise.race که به ترتیب در زمان رد شدن یا قبول شدن Promise-ها یک اتصال کوتاه ایجاد می‌کرد، Promise.allSettled همه Promise-ها را صرف نظر از رد شدن هر یک از Promise-ها اجرا می‌کند.

بنابراین می‌توانیم به صورت زیر جمع‌بندی کنیم:

  • متد Promise.allSettled اتصال کوتاه نمی‌کند و در ES2020 اضافه شده است.
  • متد Promise.all زمانی که یک مقدار ورودی رد شود، اتصال کوتاه می‌کند و. در ES6 اضافه شده است.
  • متد Promise.race زمانی که یک مقدار ورودی پذیرفته شود، اتصال کوتاه می‌کند و در ES6 اضافه شده است.

با ورود متد جدید Promise.allSettled اینک می‌توانیم یک Promise بسازیم که تنها زمانی که همه Promise-های ارسالی تکمیل شدند، بازگشت یابد. از این رو امکان دسترسی به ماتریسی با داده‌های هر Promise را فراهم می‌سازد.

const promiseOne = new Promise((resolve, reject) =>  
                       setTimeout(resolve, 3000));
const promiseTwo = new Promise((resolve, reject) => 
                       setTimeout(reject, 3000));
Promise.allSettled([promiseOne, promiseTwo]).then(data => console.log(data));
Promise {<pending>}
//(2) [{…}, {…}]
//0: {status: "fulfilled", value: undefined}
//1: {status: "rejected", reason: undefined}
//length: 2

متد String.prototype.matchAll

با فرض وجود یک رشته و یک «عبارت منظم» (regular expression)، متد ()matchAll یک تکرارکننده از همه نتایج تطبیق یافته رشته در برابر عبارت منظم بازگشت می‌دهد که شامل «گروه‌های حاصل» (Capturing Groups) است. ساختار آن به صورت str.matchAll(regexp) است:

  • regexp – یک شیء عبارت منظم است.
  • مقدار بازگشتی – یک تکرارکننده یا ‌ iterator است که تکرارشونده قابل ری‌استارت نیست.

گروه‌های حاصل در زمان استفاده از ()match با فلگ سراسری /g نادیده گرفته می‌شوند:

const regexp = /g(ro)(up(\d?))/g;
const groups = 'group1group2group3';
groups.match(regexp);
//(3) ["group1", "group2", "group3"]
//0: "group1"
//1: "group2"
//2: "group3"

با استفاده از matchAll می‌توان به گروه‌های حاصل دسترسی یافت:

const regexp = /g(ro)(up(\d?))/g;
const someString = 'group1group2group3';
const array = [...someString.matchAll(regexp)];
array
//(3) [Array(4), Array(4), Array(4)]
//0: (4) ["group1", "ro", "up1", "1", index: 0, input: //"group1group2group3", groups: undefined]
//1: (4) ["group2", "ro", "up2", "2", index: 6, input: //"group1group2group3", groups: undefined]
//2: (4) ["group3", "ro", "up3", "3", index: 12, input: //"group1group2group3", groups: undefined]
//length: 3

عملگر زنجیره‌سازی اختیاری

زنجیره‌های طولانی از دسترسی به مشخصه‌ها مستعد بروز خطا هستند و بررسی وجود مشخصه روی هر گام به یک ساختار تودرتوی عمیق منتهی می‌شود. به مثال زیر که در مورد یک شیء ساده خودرو (Car) است، توجه کنید:

let car = {
  engine : {
    consumption: 10
  }
}

فرض کنید می‌خواهیم به مصرف سوخت (consumption) دسترسی پیدا کنیم، این کار به صورت زیر انجام می‌یابد:

let consumption = car.engine.consumption
//console.log(consumption)
//10 Ok, no problem here.

اما اگر engine مقدار null داشته باشد، چطور می‌شود؟ در این صورت اگر تلاش کنیم به consumption دسترسی پیدا کنیم، با یک خطا مواجه خواهیم شد. باید ابتدا مشخصه را بررسی کنیم:

let car = {
}
car.engine.consumption;
//Uncaught TypeError: Cannot read property 'consumption' of  
//undefined
//Before ES2020
//Check if exists
let consumption = car.engine ? car.engine.consumption : undefined
//console.log(consumption )
//undefined
/////or/////
let car = {
}
//Check if exists
let consumption;
if(car.engine && car.engine.consumption){
  let consumption = cat.engine.consumption
}else{
  let consumption = undefined
}
console.log(consumption)
//undefined

کد فوق کار می‌کند، اما بدیهی است که کد زیر بهتر است:

let car = {
}
let consumption = car.engine?.consumption
console.log(consumption);
//undefined

همچنین می‌توان از عملگر زنجیره‌سازی اختیاری استفاده کرد:

let car = null;
let consumption = car?.engine?.consumption
console.log(consumption);

زنجیره‌سازی اختیاری روی آرایه‌ها و فراخوانی‌های تابع کار می‌کند. به مثال زیر توجه کنید:

//This makes sure that array exists before trying to access the //first element.
let car1 = array?.[1];

این عملگر زنجیره‌سازی اختیاری است و کارکرد ساده و بسیار مفیدی دارد.

ایمپورت دینامیک

()Dynamic import یک شکل شبه تابع از ایمپورت معرفی می‌کند که قابلیت‌های جدیدی در قیاس با ایمپورت استاتیک دارد، مثلاً می‌توانیم از آن برای «بارگذاری کند» (lazy loading) استفاده کنیم. مورد زیر را که در فایل greetingsModule.js/. قرار دارد در نظر بگیرید:

//greetingsModule.js
export hello () => console.log("Hello World!");

در کد فوق به صورت استاتیک ایمپورت می‌کنیم و از ماژول greetings Module.js/. استفاده شده است:

//main.js
import * as greet from './ greetingsModule.js’;
greet.hello();
//Hello World!

ساختار ایمپورت استاتیک تنها در سطح فوقانی فایل می‌تواند استفاده شود. به جای آن در زمان استفاده از ایمپورت دینامیک عبارت import(module) ماژول را بارگذاری کرده و یک Promise بازگشت می‌دهد که به صورت یک شیء ماژول درمی‌‌آید که شامل همه اکسپورت‌هایش است. ضمناً می‌توانید آن را از هر جایی از کد فراخوانی کنید.

...
if( 1 === 1){
import(’./greetingsModule.js’).then( (greet) => {
             greet.hello();
            // Hello World!
         });
}
...

یا می‌توانید از async/await استفاده کنید:

...
async function load() {
    let greet = await import(’./greetingsModule.js’);
    greet.hello(); 
    // Hello!
  }
...

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

BigInt

BigInt یک شیء داخلی جدید است که روشی برای نمایش اعداد کامل بزرگ‌تر از $$2^{53}-1$$ فراهم می‌سازد. انواع عددی در جاوا اسکریپت دارای محدودیت بازه هستند و نمی‌توانند با اعداد بزرگ صحیح به درستی کار کنند. قابلیت جدید BigInt این مشکل را که در زمینه‌های مختلف که با مقادیر علمی سروکار دارند مسئله بزرگی محسوب می‌شود، حل می‌کند.

console.log(Number.MAX_SAFE_INTEGER);
//9007199254740991
const max = Number.MAX_SAFE_INTEGER;
console.log(max +1);
//9007199254740992  -> Correct value!
console.log(max +10);
//9007199254741000  -> Incorrect value! (1001)

این مشکل با استفاده از نوع داده جدید BigInt قابل حل است. با افزودن حرف n به انتهای عدد، کد زیر به دست می‌آید:

const myBigNumber = 9007199254740991n;
console.log(myBigNumber +1n);
//9007199254740992n  -> Correct value!
console.log(myBigNumber +10n);
//9007199254741001n  -> Correct value!
//Note:
console.log(myBigNumber +10);
//Error: you cannot mix BigInt and other types, use explicit //conversions.
//Correct way: You have to add the letter 'n' on the end of the //number

به این ترتیب به پایان این راهنما می‌رسیم.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
شما قبلا رای داده‌اید!
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.

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