مقدمه
قبلا تو مقاله ی ” ورژن بندی اکما اسکریپت (جاوا اسکریپت) ” از مجله آموزشی ویکس سون، امکانات و فیچرهایی که تو Es12 به جاوا اسکریپت اضافه شده رو معرفی کردیم. در ادامه به جزییات این قابلیت ها و آموزششون میپردازیم.
امکانات و قابلیت های جاوا اسکریپت Es12 (2021)
- متد Promise.any در پرامیس ها و خطای AggregateError
- متد String.prototype.replaceAll در استرینگ (رشته) ها
- جداکننده عددی (Numeric Separators)
- آبجکت WeakRef (Weak References)
- تعریف فیلدها و متدهای خصوصی (Private) در کلاس ها
- تعریف فیلدها و متدهای ایستا (Static) در کلاس ها
- بلاک های تعریف ایستا (Static Initialization Blocks) در کلاس ها
آموزش کامل جاوا اسکریپت Es12 (2021)
(با توجه به اینکه این ورژن، ورژن نسبتا جدیدی به حساب میاد، با احتیاط از فیچرهاش استفاده کنید)
پیشنیاز این آموزش :
- آشنایی با مفاهیم پایه جاوا اسکریپت
- آشنایی با قابلیت های جدید جاوا اسکریپت تا اکما اسکریپت 2020 یا Es11
1) متد Promise.any در پرامیس ها و خطای AggregateError در جاوا اسکریپت Es12
const promise1 = new Promise((res, rej) => setTimeout(res, 2000));
const promise2 = new Promise((res, rej) => setTimeout(rej, 2000));
console.log(Promise.any([promise1, promise2]));
/* output:
[[PromiseState]]: "fulfilled"
*/
نکته : اگه هیچکدوم از پرامیس ها fulfill نشن، ارور AggregateError دریافت میکنیم. در واقع این ارور زمانی رخ میده که چند ارور به صورت همزمان رخ میدن (مثل همینجا که چند ارور مربوط به reject شدن پرامیس ها داریم). یکی از حالت هایی که این متد کامل reject میشه و ارور AggregateError نمایش داده میشه اینه که یه آرایه خالی تو ورودیش ارسال کنیم :
Promise.any([]); // Uncaught (in promise) AggregateError: All promises were rejected
2) متد String.prototype.replaceAll در استرینگ (رشته) های جاوا اسکریپت Es12
حتما میدونید که قبلا میتونستیم به کمک متد replace ، کاراکتر یا کلمه مورد نظرمون رو با یه کاراکتر یا کلمه دیگه جایگزین کنیم. مشکلی که وجود داشت این بود که این متد، جایگزینی رو فقط برای اولین نتیجه انجام میداد (البته میتونستیم به کمک رجکسی که با فلگ g نوشته میشد کل متن رو جستجو کنیم). مثلا تو کد زیر wix-mag جایگزین اولین wix7 موجود توی متن میشه :
let string = "We are wix7 and this is wix7 javascript tutorial";
console.log(string.replace("wix7", "wix-mag")); // output: We are wix-mag and this is wix7 javascript tutorial
متد replaceAll این امکان رو برامون فراهم کرده که بتونیم همه ی نتایج رو جایگزین کنیم. بازنویسی کد بالا با متد replaceAll :
let string = "We are wix7 and this is wix7 javascript tutorial";
console.log(string.replaceAll("wix7", "wix-mag")); // output: We are wix-mag and this is wix-mag javascript tutorial
همونطور که میبینید هر دو نتیجه جایگزین شدن
نکته : تو متد replaceAll هم مثل متد replace میشه از رجکس به عنوان پارامتر اول برای جستجو استفاده کرد، با توجه به این نکته که حتما فلگ رجکس باید گلوبال (g) باشه.
3) جداکننده عددی (Numeric Separators) در جاوا اسکریپت Es12
شاید سخت باشه که تو نگاه اول به یه عدد بزرگ، بتونیم تشخیص بدیم که دقیقا چه عددیه. کمتر کسی میتونه خیلی سریع حدس بزنه که مثلا “90000000” معادل نود میلیونه. به همین خاطره که موقع نوشتن این اعداد، هر سه رقم رو با یه کاراکتر خاص مثل , یا / جدا میکنیم. جاوا اسکریپت تو Es12 کاراکتر آندرلاین (_) رو در اختیارمون گذاشته تا توی سورس کدمون ازش استفاده کنیم که قطعا خوانایی اعداد رو بالا میبره. به عنوان مثال 90 میلیون رو به صورت زیر میتونیم تو سورس کدمون بنویسیم، در حالیکه تو خروجی به صورت عادی نمایش داده میشه و مشکلی ایجاد نمیکنه :
console.log(90_000_000); // output: 90000000
4) آبجکت WeakRef (Weak References) در جاوا اسکریپت Es12
WeakRef مخفف Weak References به معنی رفرنس ضعیف هست. برای اینکه WeakRef رو بشناسید، اول باید Strong (Normal) References رو بشناسید. همونطور که میدونید جاوا اسکریپت قابلیت Garbage Collector داره، به این معنی که برای مدیریت بهتر حافظه، آبجکت هایی که رفرنس قوی ندارن رو شناسایی و پاک میکنه تا اون فضا رو بتونه به آبجکت های جدید اختصاص بده. اگه از WeakRef به عنوان رفرنس برای یه آبجکت استفاده کنیم، در واقع این اجازه رو به Garbage Collector دادیم که بتونه آبجکت رو پاک کنه (برعکس رفرنس های قوی).
دستورهای اصلی WeakRef :
-
- ()new WeakRef : برای ساخت رفرنس ضعیف
- ()WeakRef.prototype.deref : برای دسترسی به آبجکت هدف (target object)
نکته : به آبجکتی که WeakRef براش تعریف میشه، target یا referent گفته میشه.
نکته : از اونجایی که استفاده از این قابلیت نیاز به تسلط بالا و دقت زیاد داره، مراجع رسمی و معتبر جاوا اسکریپت از جمله TC39 و MDN توصیه میکنن که تا جای ممکن از این فیچر استفاده نشه. به همین خاطر ما هم بیشتر از این بهش نمیپردازیم. اگه علاقه داشته باشین میتونید از رفرنس هایی که قرار دادیم برای مطالعه بیشتر استفاده کنید.
5) تعریف فیلدها و متدهای خصوصی (Private) در کلاس های جاوا اسکریپت Es12
جاوا اسکریپت، اخیرا توجه بیشتری به برنامه نویسی شی گرا داشته و تیم اکما سعی کرده که امکانات و مفاهیمی که تو سایر زبان های برنامه نویسی شی گرا مثل جاوا و سی پلاس پلاس مهیا هست رو تو جاوا اسکریپت هم پیاده سازی کنه. یکی از این قابلیت ها، امکان تعریف فیلدها و متدها با سطح دسترسی Private تو کلاس ها یا بصورت خلاصه فیلدها و متدهای خصوصی هست.
خیلی ساده اگه بخوایم بگیم، فیلدها و متدهای خصوصی (private)، شبیه فیلدها و متدهای معمولی (public) هستن با این تفاوت که با کاراکتر هش (#) تعریف میشن (یعنی کافیه فقط اول اسم فیلد یا متد، # بذاریم)، به همین سادگی! مثلا تو کد زیر 2 فیلد و 2 متد خصوصی و عمومی ساختیم :
class Private {
publicField = 1;
#privateField = 2;
publicMethod() {
return this.publicField + 10;
}
#privateMethod() {
return this.#privateField + 10;
}
}
اما بیاین بحث رو یکم باز کنیم و ببینیم که چرا اصلا این کار رو انجام میدیم و تفاوت دیتاهای private با public داخل کلاس ها چیه؟ برای شروع باید یه زبان مشترک با هم پیدا کنیم، لازمه این زبان مشترک اینه که یه سری مفاهیم و تعریف های مربوط به کلاس ها رو با هم مرور کنیم. همونطور که میدونید از کلاس ها برای برنامه نویسی شی گرا توی جاوا اسکریپت استفاده میشه. مفاهیم مهمی که در مورد کلاس ها باید بدونیم :
-
- فیلد (fields) : فیلدها در واقع متغیرهاهایی هستن که “خصوصیات کلاس” رو تعیین میکنن. فیلدها مثل متغیرها تعریف میشن با این تفاوت که نیازی به نوشتن var, let, const نیست.
- متد (merhods) : متد ها در واقع توابعی هستن که “رفتار کلاس” رو تعیین میکنن، برخلاف توابع معمولی که با function تعریف میشن، این متدها فقط با نوشتن نامشون به همراه پرانتر () تعریف میشن.
- ارث بری (inheritance) : اگه بخوایم کلاس جدیدی بنویسیم که قسمتی از اون، مشابه کلاس اصلی باشه، به جای اینکه کدها رو بازنویسی کنیم، این کلاس جدید رو به عنوان فرزند کلاس اصلی تعریف میکنیم تا ویژگی های کلاس اصلی (والد) رو به ارث ببره. این کار به کمک کلمه کلیدی extend انجام میشه.
و اما تو برنامه نویسی شی گرا (اکثر زبان ها) 3 سطح دسترسی داریم :
-
- public : فیلد یا متد، محدودیتی از نظر دسترسی نداره و همه جا میشه فراخوانیش کرد (داخل کلاس، بیرون کلاس، داخل کلاس های فرزند)
- private : فیلد یا متد، فقط داخل کلاس اصلی در دسترسه
- protected : فیلد یا متد، داخل کلاس اصلی و داخل کلاس های فرزند در دسترسه
حالا که با این مفاهیم آشنا شدیم میتونیم رفتار فیلدها و متدهای private رو بررسی کنیم. همونطور که متوجه شدین، اگه فیلد یا متدی رو به صورت private تعریف کنیم، فقط داخل کلاسی که تعریف میشه قابل دسترسه و از بیرون کلاس نمیشه بهش دسترسی داشت (حتی داخل کلاس های فرزند هم نمیشه). در حالت عادی ما میتونیم از بیرون کلاس اطلاعات داخل کلاس رو دستکاری کنیم. مثلا تو کد زیر متدی رو تعریف کردیم که یه عدد رو از ورودی میگیره و با 10 جمع میکنه. ما از بیرون کلاس یه شی ساختیم و به کمک این شی یه مقدار جدید (20) رو برای فیلد داخل کلاس تعریف کردیم و به این شکل تو عملکرد متد اختلال ایجاد کردیم و حاصل به جای 15، 25 شد :
class Sum {
constNumber = 10;
addNumber(number) {
this.constNumber += number;
return this.constNumber;
}
}
const myNumber = new Sum();
myNumber.constNumber = 20;
console.log(myNumber.addNumber(5)); // output: 25
کاربرد فیلد private اینجا مشخص میشه. اگه فیلد constNumber رو به صورت خصوصی تعریف کنیم، دستکاری از بیرون غیرممکن میشه. ببینید :
class Sum {
#constNumber = 10;
addNumber(number) {
this.#constNumber += number;
return this.#constNumber;
}
}
const myNumber = new Sum();
myNumber.constNumber = 20;
console.log(myNumber.addNumber(5)); // output: 15
نکته : به این عمل (مخفی کردن اطلاعات حساس از دید کاربر)، کپسوله سازی یا Encapsulation میگن.
نکته : به کمک اکسسور پراپرتی ها (getter و setter) میتونیم تعیین کنیم که تحت شرایط خاص (برقراری شرط) دسترسی از بیرون کلاس به دیتای private ممکن باشه. اما باید توجه کنیم که خود اکسسور ها باید به صورت public تعریف بشن تا بیرون کلاس در دسترس باشن.
6) تعریف فیلدها و متدهای ایستا (Static) در کلاس های جاوا اسکریپت Es12
تا حالا به این فکر کردین که آیا راهی هست که بشه بدون اینکه از روی کلاس نمونه ای بسازیم، مستقیما به فیلد یا پراپرتی کلاس دسترسی داشته باشیم ؟ این امکان تو جاوا اسکریپت Es12 ارائه شده تا به کمک کلمه کلیدی static بتونیم فیلدها و متدهایی تعریف کنیم که خارج از کلاس بدون تعریف نمونه بتونیم بهشون دسترسی داشته باشیم. به عنوان مثال کد زیر رو ببینید :
class Test {
static field = "Static Field";
static method() {
return "Static Method";
}
}
console.log(Test.field); // output: Static Field
console.log(Test.method()); // output: Static Method
دیتای static بین همه ی نمونه هایی که از یک کلاس ساخته میشن، مشترکه و فقط یکبار به همراه کلاس تعریف میشه. برعکسه دیتاهای معمولی که با هر بار ساخته شدن نمونه، مجددا تعریف میشن. پس بهتره جایی که نمیخوایم یه دیتا، برای هر نمونه، منحصر به فرد باشه، به صورت static تعریفش کنیم تا کدمون پرفورمنس بهتری داشته باشه و تو مصرف منابع صرفه جویی بشه.
نکته : دیتاهای static به صورت private هم تعریف میشن. برای اینکار کافیه که از کلمه کلیدی static و کاراکتر هش # همزمان استفاده کنیم. اگه مقادیر static به صورت private تعریف بشن، دیگه خارج از کلاس در دسترس نیستن و فقط داخل کلاس میشه ازشون استفاده کرد.
نکته : به همه ی مقادیر خصوصی داخل کلاس ها (ایستا و غیر ایستا)، Private Properties گفته میشه که اینجا با 4 تاشون آشنا شدیم :
- Private fields
- Private methods
- Private static fields
- Private static methods
7) بلاک های تعریف ایستا (Static Initialization Blocks) در کلاس های جاوا اسکریپت Es12
فرض کنید یه تابع خارج از کلاس داریم که مسئول برقراری ارتباط با دیتابیس هست. داخل کلاس میخوایم ارتباط با دیتابیس رو چک کنیم و بعد نمونه ها از روی کلاس ساخته بشن. خب اگه قرار باشه این تابع رو داخل کلاس فراخوانی کنیم، با هر بار فراخوانی کلاس برای ساختن نمونه، ارتباط با دیتابیس باید چک بشه که معقول نیست. به همین خاطر یه بلاک static داخل کلاس تعریف میکنیم و تابع رو داخل این بلاک فراخوانی میکنیم.
کدهایی که داخل بلاک static قرار میگیرن، فقط یکبار به همراه کلاس تعریف میشن. به عنوان مثال تو کد زیر هرچند کلاس رو دو نمونه ساخته شده (کلاس دوبار فراخوانی شده)، ولی فقط یکبار پیام اتصال دیتابیس رو تو کنسول میبینیم :
const createDBConnection = () => {
console.log("Database connection created");
};
class Connection {
static {
createDBConnection();
}
}
const a = new Connection();
const b = new Connection();
نکته : تعداد بلاک های static داخل یک کلاس میتونه بیشتر از یکی باشه و از بالا به پایین اجرا میشه. و اجرای این بلاک ها به constructor ارجحیت داره یعنی حتی اگه بلاک static بعد از constructor نوشته بشه، اول بلاک static اجرا میشه. مثلا تو کد زیر اول تو کنسول نمایش داده میشه، بعد و بعد :
class Connection {
static {
console.log("Block 1");
}
constructor() {
console.log("Constructor");
}
static {
console.log("Block 2");
}
}
const a = new Connection();
/*
Block 1
Block 2
Constructor
*/
جمع بندی
شاید بشه گفت که جاوا اسکریپت Es12، ورژن کلاس ها و برنامه نویسی شی گرا بود. البته رفرنس های مختلف، سال های مختلفی رو برای ارائه این قابلیت ها اعلام کردن (از 2019 تا 2022) ولی به احتمال زیاد مربوط به همین ورژن و همین سال یعنی سال 2021 هست.
اگه ایرادی تو آموزش دیدین یا سوالی داشتین خوشحال میشیم تو قسمت نظرات مطرح کنید.
پیروز باشید.