WiX/mag

ویکس مگ / مجله آموزشی ویکس سِوِن

آموزش جاوا اسکریپت Es12 - اکما اسکریپت 2021

آموزش کامل جاوا اسکریپت Es12 (اکما اسکریپت 2021)

پیمان باقری

پیمان باقری

برنامه نویس و متخصص وب

مقدمه

قبلا تو مقاله ی ” ورژن بندی اکما اسکریپت (جاوا اسکریپت) ” از مجله آموزشی ویکس سون، امکانات و فیچرهایی که تو Es12 به جاوا اسکریپت اضافه شده رو معرفی کردیم. در ادامه به جزییات این قابلیت ها و آموزششون میپردازیم.

 

امکانات و قابلیت های جاوا اسکریپت Es12 (2021)

  1. متد Promise.any در پرامیس ها و خطای AggregateError
  2. متد String.prototype.replaceAll در استرینگ (رشته) ها
  3. جداکننده عددی (Numeric Separators)
  4. آبجکت WeakRef (Weak References)
  5. تعریف فیلدها و متدهای خصوصی (Private) در کلاس ها
  6. تعریف فیلدها و متدهای ایستا (Static) در کلاس ها
  7. بلاک های تعریف ایستا (Static Initialization Blocks) در کلاس ها

 

آموزش کامل جاوا اسکریپت Es12 (2021)

(با توجه به اینکه این ورژن، ورژن نسبتا جدیدی به حساب میاد، با احتیاط از فیچرهاش استفاده کنید)

پیشنیاز این آموزش :

  1. آشنایی با مفاهیم پایه جاوا اسکریپت
  2. آشنایی با قابلیت های جدید جاوا اسکریپت تا اکما اسکریپت 2020 یا Es11

     

    1) متد Promise.any در پرامیس ها و خطای AggregateError در جاوا اسکریپت Es12

    قبلا تو پست ” جاوا اسکریپت Es11 ” به متدهای Concurrency (همزمانی) پرامیس ها پرداختیم و گفتیم که این متد ها برای مدیریت بهتر پردازش های ناهمگام (async) معرفی شدن. در واقع به کمک این متدها میتونیم چند پرامیس رو همزمان مدیریت کنیم. یکی از این متدها، متد Promise.any هست که ورودیش یه دیتای قابل پیمایش از پرامیس هاست (مثلا آراایه ای از پرامیس ها) و خروجیش هم یه تک پرامیسه که اگه حداقل یکی از پرامیس ها fulfill بشه، fulfill میشه.

    به عنوان مثال تو کد زیر 2 تا پرامیس (که یکی reject شده و یکی fulfill)، به عنوان ورودی به Promise.any پاس دادم. همونطور که انتظار داریم، پرامیس fulfill شده :
    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

    رفرنس : MDN / jstut

     

    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) باشه.

    رفرنس : MDN / G4G

     

    3) جداکننده عددی (Numeric Separators) در جاوا اسکریپت Es12

    شاید سخت باشه که تو نگاه اول به یه عدد بزرگ، بتونیم تشخیص بدیم که دقیقا چه عددیه. کمتر کسی میتونه خیلی سریع حدس بزنه که مثلا “90000000” معادل نود میلیونه. به همین خاطره که موقع نوشتن این اعداد، هر سه رقم رو با یه کاراکتر خاص مثل , یا / جدا میکنیم. جاوا اسکریپت تو Es12 کاراکتر آندرلاین (_) رو در اختیارمون گذاشته تا توی سورس کدمون ازش استفاده کنیم که قطعا خوانایی اعداد رو بالا میبره. به عنوان مثال 90 میلیون رو به صورت زیر میتونیم تو سورس کدمون بنویسیم، در حالیکه تو خروجی به صورت عادی نمایش داده میشه و مشکلی ایجاد نمیکنه :

    console.log(90_000_000); // output: 90000000

    رفرنس : V8/ jstut

     

    4) آبجکت WeakRef (Weak References) در جاوا اسکریپت Es12

    WeakRef مخفف Weak References به معنی رفرنس ضعیف هست. برای اینکه WeakRef رو بشناسید، اول باید Strong (Normal) References رو بشناسید. همونطور که میدونید جاوا اسکریپت قابلیت Garbage Collector داره، به این معنی که برای مدیریت بهتر حافظه، آبجکت هایی که رفرنس قوی ندارن رو شناسایی و پاک میکنه تا اون فضا رو بتونه به آبجکت های جدید اختصاص بده. اگه از WeakRef به عنوان رفرنس برای یه آبجکت استفاده کنیم، در واقع این اجازه رو به Garbage Collector دادیم که بتونه آبجکت رو پاک کنه (برعکس رفرنس های قوی).

    دستورهای اصلی WeakRef :

      1. ()new WeakRef : برای ساخت رفرنس ضعیف
      2. ()WeakRef.prototype.deref : برای دسترسی به آبجکت هدف (target object)

    نکته : به آبجکتی که WeakRef براش تعریف میشه، target یا referent گفته میشه.

    نکته : از اونجایی که استفاده از این قابلیت نیاز به تسلط بالا و دقت زیاد داره، مراجع رسمی و معتبر جاوا اسکریپت از جمله TC39 و MDN توصیه میکنن که تا جای ممکن از این فیچر استفاده نشه. به همین خاطر ما هم بیشتر از این بهش نمیپردازیم. اگه علاقه داشته باشین میتونید از رفرنس هایی که قرار دادیم برای مطالعه بیشتر استفاده کنید.

    رفرنس : MDN / V8

     

    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 داخل کلاس ها چیه؟ برای شروع باید یه زبان مشترک با هم پیدا کنیم، لازمه این زبان مشترک اینه که یه سری مفاهیم و تعریف های مربوط به کلاس ها رو با هم مرور کنیم. همونطور که میدونید از کلاس ها برای برنامه نویسی شی گرا توی جاوا اسکریپت استفاده میشه. مفاهیم مهمی که در مورد کلاس ها باید بدونیم :

      1. فیلد (fields) : فیلدها در واقع متغیرهاهایی هستن که “خصوصیات کلاس” رو تعیین میکنن. فیلدها مثل متغیرها تعریف میشن با این تفاوت که نیازی به نوشتن var, let, const نیست.
      2. متد (merhods) : متد ها در واقع توابعی هستن که “رفتار کلاس” رو تعیین میکنن، برخلاف توابع معمولی که با function تعریف میشن، این متدها فقط با نوشتن نامشون به همراه پرانتر () تعریف میشن.
      3. ارث بری (inheritance) : اگه بخوایم کلاس جدیدی بنویسیم که قسمتی از اون، مشابه کلاس اصلی باشه، به جای اینکه کدها رو بازنویسی کنیم، این کلاس جدید رو به عنوان فرزند کلاس اصلی تعریف میکنیم تا ویژگی های کلاس اصلی (والد) رو به ارث ببره. این کار به کمک کلمه کلیدی extend انجام میشه.

    و اما تو برنامه نویسی شی گرا (اکثر زبان ها) 3 سطح دسترسی داریم :

      1. public : فیلد یا متد، محدودیتی از نظر دسترسی نداره و همه جا میشه فراخوانیش کرد (داخل کلاس، بیرون کلاس، داخل کلاس های فرزند)
      2. private : فیلد یا متد، فقط داخل کلاس اصلی در دسترسه
      3. 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 تعریف بشن تا بیرون کلاس در دسترس باشن.

    رفرنس : MDN / jstut

     

    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

    رفرنس : MDN / jsinfo

     

    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
    */

    رفرنس : MDN / V8

     

    جمع بندی

    شاید بشه گفت که جاوا اسکریپت Es12، ورژن کلاس ها و برنامه نویسی شی گرا بود. البته رفرنس های مختلف، سال های مختلفی رو برای ارائه این قابلیت ها اعلام کردن (از 2019 تا 2022) ولی به احتمال زیاد مربوط به همین ورژن و همین سال یعنی سال 2021 هست.

    اگه ایرادی تو آموزش دیدین یا سوالی داشتین خوشحال میشیم تو قسمت نظرات مطرح کنید.

    پیروز باشید.