اکما اسکریپت (ES6) چیست؟ به همراه کاربرد های آن

روز به روز اهمیت استفاده از جاوا اسکریپت پر رنگ‌ تر می‌شود، به همین دلیل توسعه دهنده هایی که با ترفند های بیشتری از این زبان آشنا باشند می‌ توانند گوی سبقت را از دیگران بربایند که در همین راستا در این مقاله به معرفی ترفند هایی از ES6 می‌پردازیم که با استفاده از آن‌ ها خواهید توانست کدهای جاوا اسکریپت بهتر و بهینه‌ تری بنویسید.اکما اسکریپت (ES6) چیست؟اکما اسکریپت زبان جدیدی نیست و فقط یک استداندارد هست که برای زبان برنامه نویسی جاوا اسکریپت تعیین شده است. اکما یک سازمان بین المللی است که کار تعریف استاندارد‌ های سیستم‌ های کامپیوتری و ارتباط سیستم‌ ها را انجام می‌دهد. این سازمان از سال 1961 کار خودش را از اروپا شروع کرده و کار تعریف استاندارد ها را بر عهده دارد و از سال 1994 با عنوان فعلی خود یعنی ECMA شناخته می‌شود.اکما اسکریپت نسخه 6 (ES6) یک استاندارد نسبتا جدید است که در سال 2015 عرضه شده است و از قابلیت‌ های جدید زیادی پشتیبانی می‌کند. این استاندارد از نظر فنی ES2015 نامیده می‌شود و هر نسخه سالانه پس از آن نیز بر اساس سال انتشار مشخص می‌شود. اما در هر حال اغلب افراد آن را ES6 می‌نامند. ES6 به طور خاص از این جهت مهم است که یک نشانه از آغاز استاندارد سازی جاوا اسکریپت محسوب می‌شود. امروزه ECMA هر سال یک نسخه جدید ارائه می‌کند.دستورات و قابلیت هایی که در ES6 اضافه شدندکلمات کلیدی let و const کلمه کلیدی const به شما امکان تعریف Constant ها را می‌دهد (که خود این کلمه کوتاه‌ شده ی Constant به معنای «ثابت» می باشد). و با let هم می‌ توان متغیر تعریف کرد اما ممکن است این سؤال برایتان پیش بیاید که مگر پیش از این در زبان جاوا اسکریپت امکان تعریف متغیر را نداشتیم؟درست است اما متغیر هایی که با var تعریف می‌شوند، اسکوپ (Scope) وسیعی دارند (یا به اصطلاح Global-Scope هستند). اما آنچه از طریق let و const ایجاد می‌گردد، اسکوپ (محدوده) مشخصی خواهد داشت که همین مسئله احتمال ایجاد باگ را به حداقل می‌رساند:function scope() {var x = 1;let y = 2;const z = 3;{var x = 100;let y = 200;const z = 300;console.log('x in block scope is', x);console.log('y in block scope is', y);console.log('z in block scope is', z);}console.log('x outside of block scope is', x);console.log('y outside of block scope is', y);console.log('z outside of block scope is', z);}scope();به طور کلی، مهم‌ ترین تفاوت بین متغیر هایی که با let و const تعریف می‌ شوند با متغیر هایی که با var تعریف می‌شوند، قابلیت دسترسی آن‌ها است. به عبارت دیگر، متغیر هایی که با let و const تعریف گردند تنها در داخل بلاک‌ هایی که تعریف شده‌ اند اعتبار دارند (در جاوا اسکریپت یک بلاک از کد با آکولاد مشخص می‌ شود. توابع (Helper Functions) مرتبط با آرایه‌ هایک سری Helper Functions جدید در ES6 عرضه شده است که کار با آرایه‌ های جاوا اسکریپت را در بسیاری از موارد آسان می‌کنند. تا به حال برایتان پیش آمده که بخواهید کارهایی همچون فیلتر کردن، چک‌ کردن همه ی المان‌ های آرایه مطابق یک شرط و یا تغییر المان‌ ها را انجام دهید؟ در ES6 به ویژگی هایی کاربردی از این زبان دسترسی دارید که این کارها را برایتان انجام می‌دهد. برای مثال، در ادامه چند نمونه از این فانکشن ها را معرفی می کنیم:فانکشن (متد) ()forEachخروجی این فانکشن روی هر المان از آرایه اعمال می‌شود. به عبارت دیگر، هر المان از آرایه را به عنوان یک مقدار یا آرگومان پاس می‌دهد:var colors = ['red', 'green', 'blue'];function print(val) {console.log(val)}colors.forEach(print);برای درک بهتر این موضوع، فرض کنید هر فانکشن مانند یک کارخانه می‌ ماند و وقتی ورودی‌ ها به این کارخانه وارد می‌ شوند، فانکشن (متد)()forEach به جای اینکه روی کل ورودی به یک‌ باره اعمال شود، روی تک‌ تک ورودی‌ ها اعمال می‌ گردد.فانکشن (متد) ()mapاین فانکشن آرایه‌‌ ای جدید با همان المان‌ ها ایجاد می‌کند به طوری که فانکشن ()map فقط هر یک از المان‌ های آرایه را به المان‌ دیگری تغییر می‌دهد:var colors = ['red', 'green', 'blue'];function capitalize(val) {return val.toUpperCase()}var capitalizedColors = colors.map(capitalize);console.log(capitalizedColors);فانکشن (متد) ()filterاین فانکشن یک آرایه ی جدید شامل بخشی از آرایه ی اصلی را می‌ سازد. به عبارت دیگر، یک آرایه ی جدید حاوی زیر مجموعه‌ ای از آرایه‌ اصلی ایجاد می‌کند:var values = [1, 60, 34, 30, 20, 5];function lessThan20(val) {return val < 20}var valuesLessThan20 = values.filter(lessThan20);console.log(valuesLessThan20);فانکشن (متد) ()findاین فانکشن اولین المانی که در شرط قبول ‌شود را پیدا کرده و در پایان خروجی را بر می‌گرداند:var people = [{name: 'Jack', age: 50},{name: 'Michael', age: 9},{name: 'John', age: 40},{name: 'Ann', age: 19},{name: 'Elisabeth', age: 16}]function teenager(person) {return person.age > 10 && person.age < 20;}var firstTeenager = people.find(teenager);console.log('First found teenager:', firstTeenager.name);فانکشن (متد) ()everyاین فانکشن هر المان از آرایه را چک می‌کند تا ببیند از تستی که توسط فانکشن ارائه شده است عبور می‌کند یا خیر و در پایان true یا false را بر می‌گرداند:var people = [{name: 'Jack', age: 50},{name: 'Michael', age: 9},{name: 'John', age: 40},{name: 'Ann', age: 19},{name: 'Elisabeth', age: 16}]function teenager(person) {return person.age > 10 && person.age < 20;}var everyoneIsTeenager = people.every(teenager);console.log('Everyone is teenager: ', everyoneIsTeenager);فانکشن (متد) ()someاین فانکشن چک می‌کند که آیا برخی از المان‌ های آرایه توسط فانکشن ارائه شده قبول می‌شوند یا خیر و در پایان true یا false را بر می‌گرداند:var people = [{name: 'Jack', age: 50},{name: 'Michael', age: 9},{name: 'John', age: 40},{name: 'Ann', age: 19},{name: 'Elisabeth', age: 16}]function teenager(person) {return person.age > 10 && person.age < 20;}var thereAreTeenagers = people.some(teenager);console.log('There are teenagers:', thereAreTeenagers);فانکشن (متد) ()reduceزمانی از ()reduce استفاده می‌کنیم که یک آرایه داریم و می‌خواهیم تمام مقادیرش را جمع کنیم. در این جا به جای اینکه از حلقه برای جمع مقادیر استفاده کنیم، از فانکشن ()reduce استفاده می‌کنیم:var array = [1, 2, 3, 4];function sum(acc, value) {return acc + value;}function product(acc, value) {return acc * value;}var sumOfArrayElements = array.reduce(sum, 0);var productOfArrayElements = array.reduce(product, 1);console.log('Sum of', array, 'is', sumOfArrayElements);console.log('Product of', array, 'is', productOfArrayElements);فانکشن‌ های <= (Arrow Functions)اجرای فانکشن‌ های بسیار ساده نیاز به کد های تکراری زیادی دارد. برای رفع این معضل، می‌توان از مفهومی تحت عنوان Arrow Functions استفاده کرد که با استفاده از این نوع فانکشن‌ ها می‌توان کدها را کوتاه‌تر و بهینه تر نوشت:var array = [1, 2, 3, 4];const sum = (acc, value) => {const result = acc + value;console.log(acc, ' plus ', value, ' is ', result);return result;}var sumOfArrayElements = array.reduce(sum, 0);کلاس‌ ها (Class)توسعه‌ دهندگانی که تجربه ی کد نویسی با سایر زبان‌ های شی گرا مثل پی‌ اچ‌ پی، سی‌ شارپ، جاوا و غیره را دارند و شروع به کدنویسی با زبان جاوا اسکریپت می‌کنند، مسلما خلاء نبود کلاس‌ ها را احساس کرده‌ اند و همین مسئله منجر به این گشت تا توسعه‌ دهندگان زبان محبوب جاوا اسکریپت مفهوم کلاس را در نسخه ی ES6 این زبان بگنجانند. در واقع‌، در این نسخه مفهوم وراثت تغییری نکرده بلکه تنها سینتکس بهتری برای ارث‌ بری Prototype ها ارائه شده است:class Point {constructor(x, y) {this.x = x;this.y = y;}toString() {return '[X=' + this.x + ', Y=' + this.y + ']';}}class ColorPoint extends Point {static default() {return new ColorPoint(0, 0, 'black');}constructor(x, y, color) {super(x, y);this.color = color;}toString() {return '[X=' + this.x + ', Y=' + this.y + ', color=' + this.color + ']';}}console.log('The first point is ' + new Point(2, 10));console.log('The second point is ' + new ColorPoint(2, 10, 'green'));console.log('The default color point is ' + ColorPoint.default());بهبود مفهوم آبجکت‌ لیترال‌ (Object Literals)در ES6 مفهوم آبجکت‌ لیترال‌ بهبود یافته‌ است به طوری که از این پس می‌ توانیم کارهایی همچون تعریف فیلد ها با اختصاص‌ دادن متغیر هایی با همان نام، تعریف فانکشن‌ ها و تعریف Property های پویا (Dynamic) را بسیار راحت‌ تر انجام دهیم:const color = 'red';const point = {x: 5,y: 10,color,toString() {return 'X=' + this.x + ', Y=' + this.y + ', color=' + this.color;},[ 'prop_' + 42 ]: 42;}console.log('The point is ' + point);console.log('The dynamic property is ' + point.prop_42);مفهوم استرینگ تمپلیت (Template Literals)کمتر توسعه‌ دهنده ای را می‌ توان یافت که علاقه داشته باشد با وصل کردن متغیر های مختلف، رشته های طولانی ایجاد کند و این در حالی است که خیلی از آن ها از خواندن سورس‌ کدهایی که به این‌ گونه نوشته شده‌ اند هم تنفر دارند. ES6 تمپلیت‌ های بسیار ساده‌ ای برای استفاده از رشته ها به همراه Placeholder برای متغیر ها معرفی کرده است:function hello(firstName, lastName) {return `Good morning ${firstName} ${lastName}!How are you?`;}console.log(hello('Jan', 'Kowalski'));آرگومان‌ های دیفالت فانکشن‌ (Argument Default Value)اگر تمایلی نداشته باشید تا همه ی پارامتر های ممکن فانکشن را ذکر کنید، می‌ توانید در نسخه ی ES6 از مقادیر دیفالت استفاده کنید:function sort(arr = [], direction = 'ascending') {console.log('I\'m going to sort the array', arr, direction);}sort([1, 2, 3]);sort([1, 2, 3], 'descending');اپراتور ... (Spread)اپراتور ... می‌ تواند جهت ایجاد یک کپی از روی چیزی همچون یک آرایه و موارد دیگر مورد استفاده قرار گیرد:var array = ['red', 'blue', 'green'];var copyOfArray = [...array];console.log('Copy of', array, 'is', copyOfArray);console.log('Are', array, 'and', copyOfArray, 'same?', array === copyOfArray);به منظور ادغام آرایه‌ ها هم خواهیم داشت:var defaultColors = ['red', 'blue', 'green'];var userDefinedColors = ['yellow', 'orange'];var mergedColors = [...defaultColors, ...userDefinedColors];console.log('Merged colors', mergedColors);اگر بخواهیم چند پارامتر اولیه ی فانکشنی را به متغیر ها متصل کنیم و پارامتر های دیگر که باقی می‌ مانند را به عنوان آرایه به متغیر های تکی متصل کنیم، در ES6 به راحتی چنین امکانی فراهم شده است:function printColors(first, second, third, ...others) {console.log('Top three colors are ' + first + ', ' + second + ' and ' + third + '. Others are: ' + others);}printColors('yellow', 'blue', 'orange', 'white', 'black');مفهوم Destructuringاین مفهوم می‌ تواند المان‌ های درخواستی از آرایه را استخراج کند (بیرون بکشد) و به متغیر ها اختصاص دهد:function printFirstAndSecondElement([first, second]) {console.log('First element is ' + first + ', second is ' + second);}function printSecondAndFourthElement([, second, , fourth]) {console.log('Second element is ' + second + ', fourth is ' + fourth);}var array = [1, 2, 3, 4, 5];printFirstAndSecondElement(array);printSecondAndFourthElement(array);همچنین این مفهوم می‌تواند Property های درخواستی از آبجکت را استخراج کند و آن‌ ها را به متغیر هایی با اسامی مشابه به عنوان Property اختصاص دهد:function printBasicInfo({firstName, secondName, profession}) {console.log(firstName + ' ' + secondName + ' - ' + profession);}var person = {firstName: 'John',secondName: 'Smith',age: 33,children: 3,profession: 'teacher'}printBasicInfo(person);مفهوم Promiseدر برخی از پروژه‌ ها نیاز است تا یک سری از عملیات‌ به ترتیب انجام گیرند (مثلاً تسک اول انجام شود و پس از آن تسک دوم و الی‌ آخر) اما در بسیاری از پروژه‌ ها مدیریت این دست کارها به سرعت از کنترل خارج شده و خواندن سورس‌ کد سخت می‌شود که برای حل مشکل فراخوانی کد های هم‌ زمان در جاوا اسکریپت، از مفهومی تحت عنوان Promise استفاده می‌شود.مفهوم Promise یک سری قرارداد است که نتایج تسک‌ هایی که اجرای آن‌ ها زمان زیادی طول می‌کشد را در آینده نشان می‌دهد که دارای دو نوع ورودی است: ورودی اول برای نتایج و ورودی دوم برای خطا های احتمالی که برای به دست آوردن نتایج باید یک (Callback Function) را به عنوان پارامتر then قرار دهید و برای مدیریت خطا ها هم باید (Callback Function) را به عنوان پارامتر catch قرار داد:function asyncFunc() {return new Promise((resolve, reject) => {setTimeout(() => {const result = Math.random();result > 0.5 ? resolve(result) : reject('Oppps....I cannot calculate');}, 1)});}for (let i=0; i<10; i++) {asyncFunc();.then(result => console.log('Result is: ' + result));.catch(result => console.log('Error: ' + result));}ویژگی ها و قابلیت های دیگری در ES6 معرفی شده اند اما در این مقاله به مهم ترین و پر استفاده ترین های آن ها پرداخته شد.