معرفی ویژگی های جدیدECMA Script 6
پنجشنبه 7 دی 1396وقتی جاوااسکریپت برای اولین بار ایجاد شد، احتمالا شعار آن مدیریت DOM، فرم ارسال و غیره بود. اما به آرامی و به تدریج این اسکریپت کوچک وب رشد کرد و به غول بزرگی تبدیل شد. امروزه جاوااسکریپت در مرورگرها، دستگاهها، سرورها و حتی به عنوان زبان پرس و جوی پایگاه داده مورد استفاده قرار میگیرد.
موارد استفاده از این زبان خیلی بیشتر از آن چیزی شده است که تصورش را میکردیم. ECMA Script harmony یا ES6 با برخی از تغییرات قابل توجه و ویژگیهای تنظیم شده برای ایجاد جاوااسکریپتی بهتر همراه است.
در زیر ویژگیهای جدید اضافه شده همراه با مثالها، بیشتر توضیح داده شده است. سعی کنید کدهای ES6 را تست کرده و با آنها کار کنید.
عملگر عالی نقطه نقطه نقطه
ما این ویژگی را بسیار جالب میدانیم و در همین ابتدای کار آن را به شما معرفی میکنیم. در بسیاری از مثالهای زیر کاربرد ... را میبینید. در حال حاضر شما فکر میکنید این فقط یک شیء/آرایه است که مقادیر دیگر را پس از اعلان مقدار اولیه نگه میدارد. این ویژگی میتواند بسیار مفید باشد، در جایی که انتظار دارید یک تابع تعدادی از پارامترهای نامشخص را بعد از مجموعهای مشخص از پارامترهای معین بپذیزد. برای درک بهتر میتوانید تابع printf زبان C را در نظر بگیرید.
اعلان متغیرها
ES6 تأکید کرده است که روی محدودهای از بلاکها قرار گرفته است. همان طور که بیشتر زبانها از محدوده بلاک استفاده می کنند نه از محدوده تابع، جاوااسکریپت هم از محدوده بلاک استفاده میکند. ES6 تصمیم دارد تا دو کلید واژه جدید "let" و "const" را معرفی کند. در زیر چند نکته درباره این نوع متغیرها بیان شده است.
برخلاف var، let و const دارای محدوده بلاک هستند.
متغیرهای let و const دارای temporal dead zone میباشند. یعنی دسترسی به این متغیرها قبل از اعلان آنها (در محدوده خودشان) باعث ایجاد خطای ReferenceError میشود.
نمیتوانید همان متغیر را دوبار در همان محدوده اعلان کنید. در مورد var مشکلی پیش نمیآید اما این کار برای let و const با خطا مواجه میشود.
اگر متغیر let و const به صورت سراسری تعریف شوند، برخلاف var تبدیل به ویژگی شیء سراسری نمیشوند.
مثالی از نقطه نقطه نقطه (rest)
مثال زیر را برای درک بهتر ... بیان میکنیم.
function func (argument) { let arr = [ 'a', 'b', 'c', 'd','e','f','g' ]; let [x, y, ...rest] = arr; console.log('rest is: ' + rest); // c,d,e,f,g }
توابع پیشرفتهای فوقالعادهای دارند
چند عملکرد برای مدیریت پارامترهای توابع وجود دارد. به عنوان مثال، مقادیر پیشفرض، پارامترهای نامگذاری شده، توابع arrow، لغوی و غیره که در زیر به صورت مختصر بیان شدهاند.
مقادیر پیشفرض پارامترها
میتوانید مقادیر پیشفرض را هنگام تعریف تابع ایجاد کنید. در زیر یک مثال آورده شده است.
function func (a, b=2, c=3) { console.log("a is "+a+"\n"); //a is 100 console.log("b is "+b+"\n"); //b is 200 console.log("c is "+c+"\n"); //c is 3 } func(100,200);
پارامترهای نامگذاری شده
این کار را میتوان با ES5 به این صورت انجام داد: شیءای را به عنوان پارامتر تنظیم کرده و به ویژگیهای موردنیاز از طریق آن شیء دسترسی داریم. اما ES6 نه تنها یک "someObject" را حذف میکند، بلکه شیوهای جامعتر و مناسبتر با مصرف کم حافظه در اختیار شما قرار میدهد. به مثال زیر توجه کنید.
function func (param1,{firstName,lastName}) { console.log("param1 is "+param1+"\n"); // param1 is 100 console.log("name is "+firstName+ " "+lastName+"\n"); //name is Paul Shan } func(100,{firstName:"Paul", lastName:"Shan"});
توابع Arrow
تابع Arrow یکی دیگر از ویژگیهای خوب ECMA Script 6 است. با این روش تابع را در یک خط میتوان تعریف کرد. جدا کردن ورودی و خروجی با علامت => صورت میگیرد.
//Eg:1 let p =10; console.log("p X p = "+(p=>p*p)(p)); //p X p = 100 //Eg:2 let squares = [1, 2, 3].map(x=>x*x); console.log(squares); // [1,4,9] //Eg:3 setTimeout(()=>{ console.log("Example by Void Canvas"); //Example by Void Canvas },100);
واژه this
کلمه this تغییر قابل توجهی کرده است. حالا این this دقیقا شبیه this در زبانهای strongly typed کار میکند. اما همانطور که ES6 وعده داده است 100% با موارد قبل سازگار است. this در توابع عادی تغییری نکرده است، فقط در تابع arrow تغییر کرده است.
//Example 1 : with normal function var obj={ successFunc:function () { console.log("Success"); }, testFunc:function () { setTimeout(function () { if(this.successFunc) this.successFunc(); else console.log("Failure"); },100); } } obj.testFunc(); //Failure will be printed //Example 2 : with arrow function var obj={ successFunc:function () { console.log("Success"); }, testFunc:function () { setTimeout(() => { if(this.successFunc) this.successFunc(); else console.log("Failure"); },100); } } obj.testFunc(); //Success will be printed
در مثال 1، this به شیء obj نسبت داده نشده است، بلکه به بخش اجرایی جاری اشاره میکند، که این همان رفتار عادی در ES5 است. اما در ES6 اگر از کلمه this در داخل تابع arrow استفاده کنید، فقط به شیء والد اشاره میکند، که این رفتار عادی در جاوا، سی شارپ و غیره است.
این عمل واقعا نیاز that=this را از بین خواهد برد.
نقطه نقطه نقطه در داخل تابع
بیایید ببینیم سه نقطه محبوب ما چطور به عنوان پارامترهای تابع کار میکند.
function printf (str, ...others) { var finalString = str; if(others){ others.forEach(function (val) { finalString=finalString.replace("%s",val); }); } console.log(finalString); } printf("first name is %s and last name is %s","Paul","Shan"); //first name is Paul and last name is Shan
حسن دیگر نقطه نقطه نقطه
اگر آرایهای دارید و میخواهید هر عنصری را به عنوان پارامتر تابع پاس دهید، عملگر ... دوباره به کمک شما میآید. مثال زیر را ببینید.
function func (a, b, c) { console.log("a is "+a+"\n"); //a is 100 console.log("b is "+b+"\n"); //b is 200 console.log("c is "+c+"\n"); //c is 300 } var arr = [100,200,300]; func(...arr);
شیگرایی کلاس و شیء جدید
کلاسهای ECMA Script Vanilla بسیار کارآمد بودند، اما قطعا بهترین رویکرد نبودند. آنها خیلی پیچیده بودند. ES6 رویکرد مناسبی از کلاسها ارائه میدهد که ارثبری و عملیات مربوط به OOP را بسیار شبیه به زبانهای strongly typed ایجاد میکند. مثالهای زیر را ببینید.
کلاس پایه
class Human { constructor(name, age) { this.name = name; this.age = age; } who() { return this.name + " is " + this.age + "years old."; } } let breddy = new Human("Breddy",24); console.log(breddy.who()); //Breddy is 24years old. console.log(breddy instanceof Human); //true
ارثبری
class Human { constructor(name, age) { this.name = name; this.age = age; } who() { return this.name + " is " + this.age + "years old."; } } class Student extends Human { constructor(name, age, school) { super(name, age); this.school = school; } who() { return super.who() + ' He goes to ' + this.school + " school."; } } let breddy = new Student("Breddy",24,"Havard"); console.log(breddy.who()); //Breddy is 24years old. He goes to Havard school. console.log(breddy instanceof Student); //true
همانطور که میبینید، کدها به آسانی نوشته و درک میشوند. بهترین مورد این است که به طور مستقیم میتوانید super را صدا بزنید. بدون اینکه لازم باشد super را توسط نام آن صدا بزنید.
پشتیبانی از ارثبری در کلاسها
میتوانید کلاسهای درونی جاوااسکریپت را نیز گسترش دهید. مانند آرایه، شیء، Error و غیره.
class MyError extends Error { // do your stuff } throw new MyError('An error occured!');
getterها و setterها
آنها بسیار شبیه به ES5 کار میکنند.
class MyClass { get prop() { return 'getter'; } set prop(value) { console.log('setter: '+ value); } } let inst = new MyClass(); inst.prop = 123; //setter: 123 console.log(inst.prop) //getter
متد استاتیک
class MyClass {e constructor(prop) { this.prop = prop; } static staticMethod() { return 'I am static'; } prototypeMethod() { return 'I am NOT Static'; } } let inst = new Myclass(123); console.log(inst.prototypeMethod()); //I am NOT Static console.log(MyClass.staticMethod()); //I am static console.log(MyClass.prototypeMethod()); //Error: prototypeMethod is not a function console.log(MyClass.prototype.prototypeMethod()); //I am NOT Static
اعضای غیر استاتیک نیز میتوانند با استفاده از ویژگیهای کلاس صدا زده شوند.
شباهت و تفاوت با ES5
اگر typeof کلاس را بررسی کنید. میبینید که یک تابع است. درست مثل سازنده ES5.
اما نمیتوانید کلاس یک تابع را فراخوانی کنید. این کار با خطا مواجه میشود.
ClassName.prototype غیرقابل نوشتن، غیرقابل شمارش، غیرقابل تنظیم است. با این حال *.ClassName.prototype قابل نوشتن و تنظیم هستند. اما شمارشی (enumerable) نیستند.
Hoisting (مکانیزم جاوااسکریپت که اعلان متغیرها و تابع قبل از اجرای کد به بالاترین قسمت scope خود منتقل میشوند) برای کلاسها مجاز نیست. در کلاسهای ES5 مجاز بود، اما ES6 دارای temporal dead zone برای کلاسها است.
مزایای کلاسهای ES6
برای افرادی که با سایر زبانهای strongly typed کار کردهاند بهتر است.
وراثت بسیار آسان است و نیاز به کدنویسی کمتری دارد.
برای اولین بار، ما قادر خواهیم بود تا از کلمه "super" استفاده کنیم تا کلاس پایه به طور مستقیم ارجاع شود.
ساخته شده در سازندهها
پایهای برای mixins نیز میباشد.
JS IDEs هوشمندتر شده است.
با بیشتر کدهای سابق سازگار هستند.
ماژولها در ES6
امروزه ماژولبندی در جاوااسکریپت بسیار ضروری است، زیرا برنامهها هر روز بزرگ و پیچیدهتر میشوند. در حال حاضر در دنیای جاوااسکریپت دو ماژول وجود دارد که بسیار محبوب هستند. یکی CommonJS (سبک node.js) و دیگری Asynchronous Module Definition (سبک require.js).
در ES6 ماژولها بسیار شبیه این تکنیکها هستند. در زیر مثالی را میبینید.
بررسی پایه
//defining modules //------ math.js ------ export function add(a,b) { return a+b; } export function subtract(a,b) { return a-b; } //------ main.js ------ import { add, subtract } from 'math'; console.log(add(11,2)); // 13 console.log(subtract(4, 3)); // 1 //------ main2.js -------- import * as math from 'math'; console.log(math.add(11,2)); // 13 console.log(math.subtract(4, 3)); // 1
شما میتوانید ویژگیها و متدها را از یک فایل اکسپورت کنید که به عنوان ماژولها در نظر گرفته میشوند. در برخی فایلهای دیگر میتوانید انتخاب کنید یا همه آنها را import کنید.
در main.js فقط دو تابع از math.js را import کردهایم. در حالی که main2.js تمام توابع را با یک فضای نام import کرده است.
همین کار را نیز میتوان برای CommonJS انجام داد. مثال زیر را ببینید.
function add(a, b) { return a+b; } function subtract(a, b) { return a-b; } module.exports = { add: add, subtract: subtract }; //------ main.js ------ var add = require('math').add; var subtract = require('math').subtract; console.log(add(11,2)); // 13 console.log(subtract(4, 3)); // 1 //---- main2.js ----- var math = require('math'); console.log(math.add(11,2)); // 13 console.log(math.subtract(4, 3)); // 1
default export
حالا کاری که میخواهم انجام دهم این است که میخواهم فقط یک تابع یا یک ویژگی یا کلاسی بدون هیچ نام مجزایی را اکسپورت کنم. کلمه default به شما کمک میکند تا این کار را انجام دهید. در زیر مثالی آورده شده است.
//------ Human.js ------ export default class { constructor(name){ this.name=name; } } //------ main2.js ------ import Human from 'Human'; let me = new Human("Paul");
ویژگیهای بیشتری از ماژولها
تغییر نام importها
IDهای ماژولها قابل تنظیم هستند. (پیشفرض: مسیرهای نسبی برای فایلهای ایمپورت شده)
بارگیری پروگرماتیک ماژولها از طریق API
قابلیت تنظیم در بارگیری ماژولها
قالب در ES6
این مورد یکی دیگر از ویژگیهای عالی ES2015 است. ممکن است از template engineها مثل handlebars، jade و غیره استفاده کرده باشید و از ساده بودن برنامهنویسی آنها لذت برده باشید. ES6 همراه با template engine بومی آن آمده است، که نه تنها میتوانید کد خود را قالببندی کنید، بلکه template engineها مثل handlebars قدرتمندتر و سریعتر شدهاند. در زیر چند نمونه از قالببندی در ES6 آورده شده است.
قالب ساده
قبل از این از تک کوتیشن و دابل کوتیشن استفاده میشد. ES6 از back quote استفاده میکند. قالب رشته بین دو تا back quote قرار میگیرد. در زیر یک مثال ساده آورده شده است.
let firstName = "Paul"; let lastName = "Shan"; console.log(`full name is ${firstName} ${lastName}`); //full name is Paul Shan
عملیات داخل آکولاد
میتوانید عملیات عادی را داخل }$ بگذارید.
let firstName = "Paul"; let lastName = "Shan"; console.log(`full name is ${firstName} ${lastName}. Age is ${10+10+6}`); //full name is Paul Shan. Age is 26
رشته چند خطی وجود ندارد.در ES5، اعلان یک رشته طولانی با چند خط واقعا مشکل بود. هم باید از کاراکترهای فرار استفاده میکردید و هم مجبور بودید هر خط را به طور جداگانه هماهنگ کنید. اما در ES6 با بک کوتیشن میتوانید به راحتی رشته چند خطی را بدون اینکه کدتان نمای زشت بگیرد، اعلان کنید.
//In ES5 var str = "Hi all \ I am Paul \ showing you JS examples"; console.log(str); //Hi all I am Paul showing you JS examples var str2 = "Hi all "+ "I am Paul "+ "showing you JS examples"; console.log(str); //Hi all I am Paul showing you JS examples //In ES6 let str3 = `Hi all I am Paul showing you JS examples`; console.log(str3); //Hi all //I am Paul //showing you JS examples
Template helpers
اگر یک پارامتر واحد به عنوان رشته داشته باشید (اگر از }$ برای پارامتر استفاده نشده باشد) این قالب به helper توابع به عنوان پارامتر اول فرستاده میشود. اما اگر مقدار پارامتر را برای helper ارسال کنید (با استفاده از }$) میتوانید پارامترهای جداگانهای را ارسال کنید و از آرگومان[1] این را خواهید یافت.
//Eg 1: pass a single string function getLength(str){ return str[0].length; } console.log(`length of VoidCanvas is ${getLength `VoidCanvas`}`) //Eg 2: passing multiple value let firstName = "Paul"; let lastName = "Shan"; function fullName(stringKey, value1, value2){ return value1 + " " + value2; } console.log(`full name is ${fullName `${firstName} ${lastName}`}`); //full name is Paul Shan
یک مورد پیچیده
قبلا در مورد تابع arrow و محبوبیت نقطه نقطه نقطه صحبت کردیم. مثال زیر شامل هر دوی این موارد میباشد.
//iterate on an array and print all values let templateStr = nameList => displayName` Names are as follows: ${nameList.map(name => displayName` ${name.first} ${name.last}` )} `; console.log(templateStr([ {first:"Paul", last:"Shan"}, {first:"Lois", last:"Lane"} ])); function displayName(literalSections, ...values){ let output = ""; output += recursiveArrayJoin(literalSections); output += recursiveArrayJoin(values); return output; } function recursiveArrayJoin(arr){ let output = ""; arr.forEach(element => { if(element.trim){ if(element.trim()) output+=element+ " " } else{ if(element && element.length) output += recursiveArrayJoin(element); } }); return output; }
حلقهها، تکرارکنندهها، تولیدکنندگان در ES6
ES6 یک حلقه جدید "for-of" معرفی کرده است که میتواند از طریق یک آرایه یا یک رشته (بدون شیء) تکرار شود. شاید به نظر برسد که شبیه حلقه “for-in” است، اما این طور نیست. حلقههای جدید “for-of” روی مقادیر تکرار میشوند، در حالی که “for-in” برای انجام این کار از نام ویژگی استفاده میکند. مثال زیر این مساله را روشن میکند.
مثال حلقه for-of
var myArr=["Void", "Canvas"]; var myStr = "voidcanvas.com"; var myObj={ "firstName":"Paul", "lastName":"Shan" }; for(var i in myArr){ console.log(i); // 0 1 } for(var v of myArr){ console.log(v); // Void Canvas } for(var i in myStr){ console.log(i); //0 1 2 3 4 5 6 7 8 9 10 11 12 13 } for(var v of myStr){ console.log(v); //voidcanvas.com } for(var i in myObj){ console.log(i); //firstName lastName } //ERROR: not a function. for(var v of myObj){ // Because for of is not applicable in objects console.log(v); }
تولید کنندگان (Generator)
جنریتورهای ES6 بسیار عالی هستند. چرا؟ اجازه دهید با یک مثال بگوییم. فرض کنید شما یک حلقه بینهایت را تکرار میکنید (هرچند در برنامهنویسی این کار خوب نیست، ولی حالا فرض کنید). وظایف دیگری نیز وجود دارند که منتظر اجرا هستند، اما چون جاوااسکریپت یک زبان رشته پرداز (threaded) است، این کار هرگز اجرا نخواهد شد. زیرا thread مشغول است و هیچ توقفی وجود ندارد.
//problem setTimeout(function(){ console.log("interruption!"); },100); while(true){ console.log("hello!"); }
حتی اگر حلقه بینهایت نباشد و 10000 بار تکرار شود، همچنین setTimeout() قادر به اجرای تابع برای چاپ " interruption" نخواهد بود.
اما Generator میتواند حلقه را متوقف یا قطع کند. قطع کردن حلقه در اینجا مجاز است زایرا generators از بازدهی خود در درون حلقه استفاده میکنند. مثال زیر را ببینید.
function* iteratorGenerator(arr){ for(var i=0;i<arr.length;i++){ yield arr[i] } } var arr = [1,2,3]; //declaring an iterator and running next var iterator = iteratorGenerator(arr); console.log(iterator.next()); //{"value":1,"done":false} console.log(iterator.next()); //{"value":2,"done":false} console.log(iterator.next()); //{"value":3,"done":false} console.log(iterator.next()); //{done":true} //restarting the iteration var iterator2 = iteratorGenerator(arr); console.log(iterator2.next()); //{"value":1,"done":false} console.log(iterator2.next()); //{"value":2,"done":false} console.log(iterator2.next()); //{"value":3,"done":false} console.log(iterator2.next()); //{done":true}
Symbol
Symbol چیزی شبیه به Enum است که نوع جدیدی از مقدار primitive است. بیایید ببینیم Symbol چگونه کار میکند.
بررسی کلی
var sym = Symbol(); var foo = Symbol("foo"); typeof sym; // "symbol" var symObj = new Symbol(); // TypeError var symObj = Object(sym); typeof symObj; // "object" Symbol("foo") === Symbol("foo"); // false
کاربرد
//previously var red = "red"; var green = "green"; var blue = "blue"; function handleColor(color) { switch(color) { case "red": //do your stuff case "green": //do your stuff case "blue": //do your stuff } } //with Symbol const red = Symbol(); const green = Symbol(); const blue = Symbol(); function handleColor(color) { switch(color) { case red: //do your stuff case green: //do your stuff case blue: //do your stuff } }
متدهای مهم
دو متد مهم ()Symbol.key و ()Symbol.keyFor هستند.
let foo1 = Symbol.for("foo"); // create a new symbol let foo2 = Symbol.for("foo"); // retrieve the already created symbol foo1 === foo2 // true Symbol("bar") === Symbol("bar"); // false var globalSym = Symbol.for("foo"); // create a new global symbol Symbol.keyFor(globalSym); // "foo"
اطلاعات بیشتر در مورد اشیای ES6
اجازه دهید برخی از کتابخانهها و متدهای جدید ES6 را با چند مثال کوچک بررسی کنیم.
Map
let map = new Map(); let obj = {a:1}; let func = function(){ var a=1; } map.set(obj, 123); map.set(func, "This is fun"); console.log(map.size); // 2 console.log(map.get(obj)); // 123 console.log(obj); // {"a":1} console.log(map.get(func)); // This is fun console.log(map.has(obj)); // true map.delete(obj); console.log(map.has(obj)); // false
Map چیزی جز یک مقدار کلیدی نیست. درست مثل اشیای جاوااسکریپت. اما تفاوتهای کمی وجود دارد. آنها به صورت زیر هستند:
ویژگی کلیدی یک شیء فقط میتواند رشته باشد، در حالی که کلید Map میتواند رشته، شیء، تابع یا هر چیز دیگری باشد.
اگر شما تکرار را روی Map انجام دهید، آنها دقیقا به ترتیب مقادیری که قرار داده شدهاند تکرار میشوند، در حالی که در مورد اشیا اینگونه نیست.
با استفاده از map.size به راحتی میتوانید سایز آن را به دست آورید. اما در مورد اشیاء باید سایز را به صورت دستی پیدا کنید.
Set
let set1 = new Set(); set1.add('hello'); set1.add('hello'); console.log(set1.has('hello')); // true console.log(set1.has('world')); // false let set2 = new Set([3,2,1,3,2,3]); console.log(set2.size); //3 console.log(set2.values()); // {3,2,1} - it returns unique values in insertion order console.log(set2.entries()); // {[3,3],[2,2],[1,1]} - it returns all the values inserted
Set شیءای برای ذخیره یونیک اولیه است. با این حال اگر بخواهید مقداری تکراری اضافه کنید خطایی رخ نمیدهد اما مقدار یونیک را ست میکند.
()Object.assign
حالا ()Object.assign به راحتی دو شیء را گسترش داده یا ترکیب میکند. در زیر مثالی آورده شده است.
var one = {a:1}; var two = {b:2}; Object.assign(one,two); console.log(one); // {"a":1,"b":2} console.log(two); // {"b":2}
تنظیمات بیشتر در ES6
متد زیر متعلق به String.prototype است. ما عنوان ()String.method را برای درک بهتر ذکر میکنیم. مثالهای زیر کاربردها را بیان میکنند.
(String.repeat(int
'abc'.repeat(3); // abcabcabc 'abc'.repeat(3.6); // abcabcabc 'abc'.repeat("2"); // abcabc 'abc'.repeat(-1); //range error
(String.startsWith(string
'abc'.startsWith('ab'); // true '123'.startsWith(1); // true 'abc'.startsWith('b'); // false
(String.endsWith(string
'abc'.endsWith('bc'); // true '123'.endsWith(3); // true 'abc'.endsWith('b'); // false
(String.contains(string
'abc'.contains('bc'); // true '123'.contains(3); // true 'abc'.contains('x'); // false
اطلاعات بیشتر در مورد آرایههای ES6
متد زیر متعلق به Array.prototype است. ما عنوان ()Array.method را برای درک بهتر ذکر میکنیم.
(Array.find(arrow=>function
این دستور اولین عنصر را پیدا میکند و آنجا متوقف میشود.
var a=[13,7,8,22].find(x => x % 2 === 0) console.log(a); //8
(Array.findIndex(arrow=>function
این دستور ایندکس اولین رخداد را پیدا میکند.
var a=[13,7,8,22].findIndex(x => x % 2 === 0) console.log(a); //2
- Java Script
- 2k بازدید
- 3 تشکر