البحث في الموقع
المحتوى عن 'const'.
-
تطوّرت لغة البرمجة جافاسكريبت كثيرا خلال السنوات القليلة الماضية. إن كنت تتعلّم جافاسكريبت في 2017 دون أن تتعامل مع الإصدار ES6 فأنت تفوّت الفرصة لاستغلال طريقة يسيرة لقراءة شفرات جافاسكريبت وكتابتها. لا تقلق إن لم تكن خبيرًا في جافاسكريبت، فليس ضروريًا أن تكون ماهرًا جدًا في جافاسكريبت للاستفادة من الامتيازات التي يمنحها الإصدار ES6. سنتعرّف في هذا المقال على ميزات يقدّمها ES6 ويمكنك استخدامها يوميًا للتعوّد على الصياغة الجديدة لجافاسكريبت. الميزات الجديدة في ES6 يقدّم الإصدار ES6 الكثير من الميزات الجديدة ويضيفها إلى جافاسكريبت. يمكنك التعرّف على أهم هذه الميزات بقراءة المقاليْن التاليّيْن: ما الجديد في الإصدار القادم من جافاسكريبت (ECMAScript 6) - الجزء الأول. ما الجديد في الإصدار القادم من جافاسكريبت (ECMAScript 6) - الجزء الثاني. ليس ضروريًا أن تعرف كلّ ما يقدّمه الإصدار الجديد من أول وهلة. سأتشارك معك في هذا المقال ثلاث ميزات للبدء بها واستخدامها: الكلمتان المفتاحيّتان let وconst. الدوال السهمية Arrow functions. بالمناسبة؛ تدعم أغلب المتصفّحات الحديثة - مثل Edge، الإصدارات الحديثة من فيرفكس وكروم - ES6 جيّدًا دون الحاجة لأدوات إضافية مثل Webpack. بالنسبة للمتصفحات القديمة نسبيًا توجد مكتبات بديلة Polyfills يوفّرها مجتمع جافاسكريبت؛ ابحث عنها. ننتقل بعد التقديم إلى الميزة الأولى. الكلمتان المفتاحيّتان let وconst تُستخدَم الكلمة المفتاحية var عادة في ES5 (الإصدار القديم من جافاسكريبت) لتعريف المتغيّرات. يُمكن في ES6 إبدال var بـ let وconst؛ وهما كلمتان مفتاحيّتان لهما تأثير معتبر وتساعدان في تسهيل كتابة الشفرات البرمجية. نبدأ بإلقاء نظرة على الفرق بين let وvar لنفهم لماذا let وconst أفضل. الفرق بين let وvar بما أننا معتادون على var فسنبدأ أولاً بها. يمكننا تعريف المتغيرات بـvar ثم استخدامها بعد ذلك في أي مكان من النطاق Scope الحالي. var me = 'Zell' console.log(me) // Zell عرّفنا في المثال السابق متغيّرا عامًّا Global باسم me. نستطيع استخدام المتغيّر العام me في دالة على النحو التالي: var me = 'Zell' function sayMe () { console.log(me) } sayMe() // Zell إلا أن العكس ليس صحيحًا. إن عرّفنا متغيّرًا باسم me داخل الدالة فلن يمكننا استخدامه خارجها وسيظهر خطأ في التنفيذ: function sayMe() { var me = 'Zell' console.log(me) } sayMe() // Zell console.log(me) // Uncaught ReferenceError: me is not defined يمكننا القول إذًا إن var ذات نطاق معرَّف على مستوى الدالة Function-scoped. يعني هذا أن أي متغيّر عُرِّف داخل دالّة بـvar لن يوجد خارج هذه الدالة. إن عُرِّف المتغيّر بـvar خارج الدالة فسيكون موجودًا في النطاق الخارجي: var me = 'Zell' // النطاق العام function sayMe () { var me = 'Sleepy head' // نطاق الدالة المحلّي console.log(me) } sayMe() // Sleepy head console.log(me) // Zell بالنسبة للكلمة المفتاحية let فهي ذات نطاق معرَّف على مستوى الكتلة Block-scoped. يعني هذا أنه عند إنشاء متغيّر بـlet فستكون موجودة داخل كتلة let. لكن.. ما هي “الكتلة”؟ تُعرَّف الكتلة في جافاسكريبت بأنها كل ما يوجد بين قوسين معكوفين. في ما يلي أمثلة على الكتل: { // نطاق كتلة جديدة } if (true) { // نطاق كتلة جديدة } while (true) { // نطاق كتلة جديدة } function () { // نطاق كتلة جديدة } الفرق بين المتغيرات المعرَّفة على مستوى الدالة وتلك المعرَّفة على مستوى الكتلة كبير جدًا. إن استخدمت متغيّرات معرَّفة على مستوى الدالة فمن السهل تغيير قيمة المتغيّر دون قصد. في ما يلي مثال: var me = 'Zell' if (true) { var me = 'Sleepy head' } console.log(me) // 'Sleepy head' يظهر في المثال السابق أن المتغيّر me يأخذ القيمة “Sleepy head” بعد الخروج من كتلة التعليمة if. ربما لا تواجه مشاكل على النحو المذكور في المثال أعلاه لأنك لا تعرّف متغيّرات بنفس الاسم؛ لكن إن كنت ممّن يستخدم var في حلقات for التكرارية فربما تصادف بعضًا من الأمور الغريبة التي تحدث بسبب آلية التعامل مع نطاقات المتغيّرات في جافاسكريبت. فلنتأمل الشفرة التالية التي تطبع قيمة المتغيّر i أربع مرات ثم تطبعها من جديد مع استخدام الدالة setTimeout التي تنتظر 1000 ملي ثانية (أي ثانية واحدة) قبل تنفيذ التعليمة console.log: for (var i = 1; i < 5; i++) { console.log(i) setTimeout(function () { console.log(i) }, 1000) }; مالذي تتوقّعه من الشفرة السابقة؟ نلاحظ أن المتغيّر i أخذ القيمة 5 في مرات تنفيذ الدالة setTimeout الأربع. كيف أصبحت قيمة i تساوي 5 في كل مرة تُنفّذ فيها الدالة setTimeout؟ يعود السبب في ذلك إلى أن قيمة المتغيّر i أصبحت تساوي 5 حتى قبل تنفيذ الدالة setTimeout لأول مرة. وبما أن var تعرّف المتغيّر على مستوى الدالة فإن i هو نفس المتغيّر الذي تعمل عليه الحلقة التكرارية والذي أصبح يساوي 5 أثناء انتظار setTimeout لانقضاء الأجل المحدّد (1000 ملي ثانية). للحصول على قيمة المتغيّر i التي مُرِّرت إلى الدالة setTimeout (التي تُنفّذ التعليمات متأخرة بثانية عن وقت حصولها على القيمة) فسنتحتاج إلى دالة أخرى - وليكن اسمها logLater للتأكد من أن الحلقة التكرارية for لا تغيّر قيمة i قبل تنفيذ تعليمات setTimeout: function logLater (i) { setTimeout(function () { console.log(i) }) } for (var i = 1; i < 5; i++) { console.log(i) logLater(i) }; نلاحظ طباعة قيم i الصحيحة: 1، 2، 3 و4. من الجيّد أن الأمور الغريبة التي تحدُث مع المتغيرات المعرَّفة على مستوى الدالة - مثل ما حدث مع حلقة for السابقة - يمكن تفاديها باستخدام let. باستطاعتنا إعادة كتابة المثال الأصلي الذي ينادي setTimeout دون الحاجة لكتابة دالة مستقلة، وذلك عن طريق تعريف المتغيرات بـlet: for (let i = 1; i < 5; i++) { console.log(i) setTimeout(function () { console.log(i) }, 1000) }; ستلاحظ عند تنفيذ الشفرة السابقة أن قيم i تأتي حسب المتوقع. تسهّل المتغيرات المُعرَّفة على مستوى الكتلة - كما رأينا - كتابة الشفرات البرمجية بحذف بعض المشاكل التي تواجهها المتغيرات المعرفة على مستوى الدالة. أنصح - لتسهيل الأمور - باستخدام let بدلا من var عند تعريف المتغيّرات في جافاسكريبت. ننتقل بعد أن تعرّفنا على عمل let إلى const والفرق بين الاثنتين. الفرق بين let وconst تتشابه let وconst في أنهما تعرّفان المتغيرات على مستوى الكتلة. يكمن الفرق في أن المتغيرات التي تُعرَّف بـconst لا يمكن تغيير قيمتها بعد تعريفها أول مرة. const name = 'Zell' name = 'Sleepy head' // TypeError: Assignment to constant variable. let name1 = 'Zell' name1 = 'Sleepy head' console.log(name1) // 'Sleepy head' بما أن قيم المتغيرات المعرفة بـconst لا يمكن التعديل عليها فهي مناسبة للمتغيرات ذات القيمة الثابتة. فلنفترض أن لدينا زرا لفتح نافذة منبثقة. أعرف أنه لن يكون هناك سوى زرّ واحد من هذا النوع ولن يُعدَّل عليه. استخدم const في هذه الحالة. const modalLauncher = document.querySelector('.jsModalLauncher') أفضّل دائمًا استخدام const عند تعريف المتغيّرات كل ما كان ذلك ممكنًا، لأني أتأكد من أن قيمة المتغيّر لن يُعدَّل عليها؛ في ما عدا ذلك وفي جميع الحالات المتبقية أستخدم let. الدوال السهمية يُشار إلى الدوال السهمية بالعلامة <=، وهي اختصار لإنشاء دوال مجهولة الاسم Anonymous functions. يمكن استخدام هذه الدوال في أي مكان يُمكن استخدام الكلمة المفتاحية function فيه. على سبيل المثال: let array = [1,7,98,5,4,2] // استخدام دالة مجهولة الاسم حسب الطريقة القديمة (الإصدار ES5) var moreThan20 = array.filter(function (num) { return num > 20 }) // استخدام الدوال السهمية let moreThan20 = array.filter(num => num > 20) تقلّل الدوال السهمية من حجم الشفرة البرمجية وبالتالي تكون هناك أماكن أقل للأخطاء؛ كما تسهّل فهمَ الشفرة البرمجية عند التعود على أسلوبها. فلنر التفاصيل العملية للدوال السهمية. إنشاء الدوال السهمية ربما تكون متعوّدا على إنشاء الدوال في جافاسكريبت على النحو التالي: function namedFunction() { // Do something } ولاستخدامها: namedFunction() توجد طريقة أخرى لإنشاء الدوال وهي إنشاء دالة مجهولة الاسم وإسنادها إلى متغيّر. لإنشاء دالة مجهولة الاسم فإننا نحذف الاسم من تعريف الدالة: var namedFunction = function() { // Do something } توجد طريقة ثالثة فإنشاء الدوال، وهي إنشاءها مباشرة في معامل دالة أخرى؛ وهذه هي الطريقة الأكثر انتشارًا لإنشاء الدوال مجهولة الاسم. في ما يلي مثال: // استخدام دالة مجهولة الاسم في معامل راجع Callback button.addEventListener('click', function() { // Do something }) بما أن الدوال السهمية هي اختصارات للدوال مجهولة الاسم فإنه يمكن إحلالها في أي مكان توجد به دوال مجهولة الاسم. أمثلة: // دالة عادية const namedFunction = function (arg1, arg2) { /* do your stuff */} // دالة سهمية const namedFunction2 = (arg1, arg2) => {/* do your stuff */} // دالة عادية في معامل راجع button.addEventListener('click', function () { // Do something }) // دالة سهمية في معامل راجع button.addEventListener('click', () => { // Do something }) هل لاحظت التشابه؟ في الأساس حذفنا الكلمة المفتاحية function وأبدلناها بالعلامة <= مع تغيير موضعها قليلا. هل تقتصر الدوال السهمية على إحلال <= مكان function؟ أم أن هناك تفاصيل أخرى؟ صيغة كتابة الدوال السهمية في الواقع، تختلف كتابة الدوال السهمية حسب عامليْن هما: عدد المعاملات المطلوبة الحاجة للإرجاع الضمني Implicit return (لنتيجة التنفيذ) العامل الأول هو عدد المعاملات المُممرَّرة إلى الدالة السهمية. يمكنك حذف الأقواس التي تحيط بالمعاملات إن كان لديك معامل واحد, إن لم توجد معاملات فيمكنك إبدال الأقواس () بعلامة تسطير سفلي _. الصيغ التالية كلّها صحيحة لكتابة دالة سهمية: const zeroArgs = () => {/* do something */} const zeroWithUnderscore = _ => {/* do something */} const oneArg = arg1 => {/* do something */} const oneArgWithParenthesis = (arg1) => {/* do something */} const manyArgs = (arg1, arg2) => {/* do something */} العامل الثاني في صيغة كتابة الدوال السهمية هو الحاجة لإرجاع النتيجة ضمنيا. تضيف الدوال السهمية مبدئيًا كلمة return المفتاحية إن كانت شفرة الدالة تمتدّ على سطر واحد فقط ولم تكن مضمّنة في كتلة (بين قوسين معكوفين {...}). ‘الطريقتان التاليتان في كتابة الدوال السهمية متكافئتان: const sum1 = (num1, num2) => num1 + num2 const sum2 = (num1, num2) => { return num1 + num2 } العاملان المذكوران أعلاه هما السبب في كونك تستطيع كتابة المتغيّر moreThan20 بالطريقة المختصرة التي رأيناها سابقًا: let array = [1,7,98,5,4,2] // بدون استخدام ميزات ES6 var moreThan20 = array.filter(function (num) { return num > 20 }) // باستخدام ميزات ES6 let moreThan20 = array.filter(num => num > 20) بالمختصر، الدوال السهمية رائعة. ستحتاج لبعض الوقت حتى تتعوّد عليها. حاول استخدامها ومع الزمن ستعتادها. أريد قبل إنهاء الحديث عن الدوال السهمية تعريفك بتفصيل عمليّ آخر يسبّب الكثير من الخلط عند استخدام هذه الدوال. المتغيّر this تختلف قيمة المتغيّر this المُعرَّف مسبقا حسب طريقة استدعائه. تكون قيمة المتغيّر this الكائن Window عند استدعاء المتصفّح له خارج أي دالة. console.log(this) // Window عند استدعاء المتغيّر داخل دالة بسيطة فإن قيمته ستكون الكائن العام Global object (أي الكائن Window عندما يتعلّق الأمر بالمتصفّح). function hello () { console.log(this) } hello() // Window تسند جافاسكريبت دائما الكائن Window إلى المتغيّر this عندما يُستدعى من دالة بسيطة (مثل setTimeout). عند استخدام المتغيّر داخل تابع Method فإن القيمة تكون كائن التابع: let o = { sayThis: function() { console.log(this) } } o.sayThis() // o يحيل المتغيّر this إلى الكائن المُنشَأ حديثا عند استدعائه داخل دالة مشيّدة Constructor: function Person (age) { this.age = age } let greg = new Person(22) let thomas = new Person(24) console.log(greg) // this.age = 22 console.log(thomas) // this.age = 24 أما عند استخدام المتغيّر this داخل مستمع لحدث Event listener فإن قيمته تكون العنصُر الذي أطلق الحدث: let button = document.querySelector('button') button.addEventListener('click', function() { console.log(this) // button }) يظهر من الأمثلة السابقة أن قيمة this تحدّدها الدالة التي تستدعيه. تعرّف كل دالة قيمة خاصة بها لـthis. لا تُربَط this في الدوال السهمية بقيمة جديدة أبدا، مهما كانت طريقة استدعاء الدالة. تبقى قيمة المتغيّر this مساوية دائما لقيمة this في السياق الذي توجد به الدالة السهمية. يبدو الأمر مربكًا نوعًا ما، لذا سنأخذ بضعة أمثلة للشرح. أولا؛ لا تستخدم أبدا دوال سهمية لتعريف توابع الكائنات؛ لأنك لن تستطيع حينها الإحالة إلى الكائن باستخدام المتغيّر this: let o = { // تجنّب تعريف التوابع بدوال سهمية notThis: () => { console.log(this) // Window this.objectThis() // Uncaught TypeError: this.objectThis is not a function }, // استخدم دوال عادية لتعريف التوابع objectThis: function () { console.log(this) // o }, // يمكن أيضا استخدام الاختصار التالي لتعريف التوابع objectThis2 () { console.log(this) // o } } ثانيًّا؛ من المستحسَن ألا تستخدم الدوال السهمية لإنشاء مستمعات لأحداث لأن this لن تحيل إلى العنصُر الذي ربطت به المستمع. إن فعلت فيمكنك الحصول على السياق الحقيقي لـthis باستخدام event.currentTarget: button.addEventListener('click', function () { console.log(this) // button }) button.addEventListener('click', e => { console.log(this) // Window console.log(event.currentTarget) // button }) ثالثًا؛ قد تحتاج لاستخدام this مع الدوال السهمية في أماكن تتبدّل فيها قيمة المتغيّر بدون رغبتك. الدالة setTimeout مثال على ذلك. بهذه الطريقة لن تحتاج للتعامل مع مشاكل this، that وself الاعتيادية: let o = { // Old way oldDoSthAfterThree: function () { let that = this setTimeout(function () { console.log(this) // Window console.log(that) // o }) }, // Arrow function way doSthAfterThree: function () { setTimeout(() => { console.log(this) // o }, 3000) } } الاستخدام السابق مفيد جدًا عندما تحتاج لحذف صنف Class أو إضافته بعد انقضاء مدة معينة: let o = { button: document.querySelector('button') endAnimation: function () { this.button.classList.add('is-closing') setTimeout(() => { this.button.classList.remove('is-closing') this.button.classList.remove('is-open') }, 3000) } } في الختام، استخدم الدوال السهمية في أي مكان آخر لتجعل شفرتك البرمجية أنظف كما في مثالنا السابق moreThan20: let array = [1,7,98,5,4,2] let moreThan20 = array.filter(num => num > 20) سنتعرّف في مقال لاحق على ميزات أخرى جديدة في الإصدار ES6. ترجمة - بتصرّف - للمقال Introduction to commonly used ES6 features لصاحبه Zell.
-
تعرّفنا في مقال سابق على ميزات جديدة في الإصدار ES6 من جافاسكريبت. سنتابع في هذا المقال الحديث عن الميزات الأكثر استخداما من هذا الإصدار وذلك بتناول الإضافات الجديدة التالية: المعاملات المبدئية التفكيك Destructuring. المعاملات المبدئية تتيح هذه الخاصيّة تحديد معاملات افتراضية عند تعريف الدوال. نأخذ مثالاً لتوضيح الفائدة التي نجنيها من هذا الأمر, سنفترض أننا نريد كتابة دالة تطبع اسم عضو في فريق لعبة. إن كتبنا الدالة حسب الطريقة القديمة - قبل الإصدار ES6 - فستكون شبيهة بالتالي: function announcePlayer (firstName, lastName, teamName) { console.log(firstName + ' ' + lastName + ', ' + teamName) } announcePlayer('Stephen', 'Curry', 'Golden State Warriors') // Stephen Curry, Golden State Warriors يبدو الأمر مناسبا للوهلة الأولى؛ لكن ماذا لو أردنا الإعلان عن اسم لاعب لا ينتمي لأي فريق؟ ستكون نتيجة تنفيذ الدالة أعلاه كالتالي: announcePlayer('Zell', 'Liew') // Zell Liew, undefined طبعا undefined ليس اسم فريق. سيكون من المناسب الإشعار بأن اللاعب غير منتمٍ (Unaffiliated) لأي فريق عند عدم تمرير المعامل للدالة: announcePlayer('Zell', 'Liew', 'unaffiliated') // Zell Liew, unaffiliated يمكننا تحسين الشفرة بالتحقق من تمرير المعامل إلى المتغيّر teamName بدلاً من تمرير القيمة unaffiliated في كلّ مرة: function announcePlayer (firstName, lastName, teamName) { if (!teamName) { teamName = 'unaffiliated' } console.log(firstName + ' ' + lastName + ', ' + teamName) } announcePlayer('Zell', 'Liew') // Zell Liew, unaffiliated announcePlayer('Stephen', 'Curry', 'Golden State Warriors') // Stephen Curry, Golden State Warriors يمكن تقليل الأسطُر باستخدام العوامل Ternary operators المنطقية الثلاثية ?: function announcePlayer (firstName, lastName, teamName) { var team = teamName ? teamName : 'unaffiliated' console.log(firstName + ' ' + lastName + ', ' + team) } يمكن بالاعتماد على ميزة المعاملات المبدئية في ES6 إضافة علامة = أمام اسم المعامل عند تعريف الدالة وسيأخذ المعامل تلقائية القيمة المُحدَّدة عند عدم تمرير قيمة له أثناء استدعاء الدالة. يصبح مثالنا السابق عند كتابته حسب صيغة ES6 كالتالي: const announcePlayer = (firstName, lastName, teamName = 'unaffiliated') => { console.log(firstName + ' ' + lastName + ', ' + teamName) } announcePlayer('Zell', 'Liew') // Zell Liew, unaffiliated announcePlayer('Stephen', 'Curry', 'Golden State Warriors') // Stephen Curry, Golden State Warriors لاحظ أن اسم الفريق يصبح unaffiliated عند عدم تمرير المعامل الأخير إلى الدالة. أمر أخير. يمكنك استخدام القيمة المبدئية للمعامل بتمرير undefined يدويا إلى الدالة. تفيد هذه الطريقة إذا كان المعامل الذي تريد استخدام قيمته المبدئية ليس الأخير في معطيات الدالة: announcePlayer('Zell', 'Liew', undefined) // Zell Liew, unaffiliated التفكيك يعدّ التفكيك طريقة مناسبة لاستخراج قيم من المصفوفات Arrays والكائنات Objects. توجد فروق طفيفة بين تفكيك المصفوفات وتفكيك الكائنات. تفكيك الكائنات فلنفترض أن لدينا الكائن التالي: const Zell = { firstName: 'Zell', lastName: 'Liew' } ستحتاج - للحصول على الاسم الشخصي (firstName) والاسم العائلي (lastName) من Zell إلى إنشاء متغيّريْن وإسناد كل قيمة إل متغيّر: let firstName = Zell.firstName // Zell let lastName = Zell.lastName // Liew يتيح تفكيك الكائن إنشاء هذين المتغيّرين وإسنادهما بسطر واحد: let { firstName, lastName } = Zell console.log(firstName) // Zell console.log(lastName) // Liew مالذي يحدُث هنا؟ تطلُب من جافاسكريبت عند إضافة القوسين المعكوفين على النحو الذي رأيناه أثناء تعريف المتغيّرات تطلُب إنشاء المتغيرات المذكورة وإسناد Zell.firstName إلى firstName وZell.lastName إلى lastName. تترجم جافاسكريبت - الإصدار ES6 - الشفرة التالية: let { firstName, lastName } = Zell إلى: let firstName = Zell.firstName let lastName = Zell.lastName إن سبق استخدام اسم المتغيّر فلن يكون باستطاعتنا تعريفه من جديد؛ خصوصا عند استخدام let أو const. الشفرة التالية غير صحيحة: let name = 'Zell Liew' let course = { name: 'JS Fundamentals for Frontend Developers' // ... other properties } // تتسبّب التعليمة التالية في الخطأ Uncaught SyntaxError: Identifier 'name' has already been declared let { name } = course يمكن تفادي الخطأ في الحالات السابقة بإعادة تسمية المتغيّر أثناء تفكيك الكائن باستخدام النقطتين العموديّتين : على النحو التالي: let { name: courseName } = course console.log(courseName) // JS Fundamentals for Frontend Developers يترجم مفسّر الإصدار ES6 التعليمة عند استخدام النقطتين على النحو التالي: let courseName = course.name أمر أخير بخصوص تفكيك الكائنات. عند استخراج خاصيّة غير موجودة في الكائن فإن المتغيّر يأخذ القيمة undefined: let course = { name: 'JS Fundamentals for Frontend Developers' } let { package } = course console.log(package) // undefined هل تذكر المعاملات المبدئية؟ يمكنك استخدامها لاستخراج المتغيّرات كذلك. الصياغة مطابقة لتلك المستخدمة عند تعريف الدوال: let course = { name: 'JS Fundamentals for Frontend Developers' } let { package = 'full course' } = course console.log(package) // full course يمكنك كذلك إعادة تسمية المتغيّرات مع تحديد قيم مبدئية لها: let course = { name: 'JS Fundamentals for Frontend Developers' } let { package: packageName = 'full course' } = course console.log(packageName) // full course تفكيك المصفوفات يشبه تفكيك المصفوفات تفكيك الكائنات. تُستخدَم الأقواس المُربَّعة [] بدلا من {} لاستخراج متغيّرات من المصفوفة. المتغيّر الأول بين الأقواس يأخذ قيمة العنصُر الأول في المصفوفة والمتغيّر الثاني قيمة العنصر الثاني وهكذا. let [one, two] = [1, 2, 3, 4, 5] console.log(one) // 1 console.log(two) // 2 إن حدّدت متغيرات أكثر من عناصر المصفوفة فإن المتغيرات الزائدة تأخذ القيمة undefined: let [one, two, three] = [1, 2] console.log(one) // 1 console.log(two) // 2 console.log(three) // undefined في الغالب نستخرج العناصر التي نحتاجها من المصفوفة فقط. يمكن استخدام الكلمة المفتاحية rest على النحو التالي لاستقبال بقية المصفوفة: let scores = ['98', '95', '93', '90', '87', '85'] let [first, second, third, ...rest] = scores console.log(first) // 98 console.log(second) // 95 console.log(third) // 93 console.log(rest) // [90, 87, 85] سنخصّص جزءًا من هذا المقال للحديث عن العامل rest، ولكن قبل ذلك سنتحدّث عن ميزة خاصّة عند تفكيك المصفوفات وهي مبادلة المتغيّرات Swapping variables. فلنفترض أن لدينا متغيّريْن a وb: let a = 2 let b = 3 نريد مبادلة هذين المتغيّرين بحيث تكون قيمة a تساوي 3 وقيمة b تساوي 2. نحتاج - في الإصدار ES5 - إلى استخدام متغيّر ظرفي لإكمال المبادلة: let a = 2 let b = 3 let temp // المبادلة temp = a // temp = 2 a = b // a = 3 b = temp // b = 2 فلنر الآن كيفية المبادلة في ES6 بتفكيك المصفوفات: let a = 2 let b = 3; // نحتاج لنقطة فاصلة هنا لأن السطر الموالي يبدأ بقوس معكوف مربَّع // المبادلة باستخدام ميزة تفكيك المصفوفات [a, b] = [b, a] console.log(a) // 3 console.log(b) // 2 تفكيك المصفوفات والكائنات في الدوال أروع ما في التفكيك إمكانيةُ استخدامه في أي مكان تريده. حتى إن بإمكانك تفكيك المصفوفات والكائنات في الدوال. فلنفترض أن لدينا دالة تأخذ مصفوفة من النتائج وتعيد كائنا بالنتائج الثلاث الأعلى. تشبه الدالة التالية ما فعلناه عند تفكيك المصفوفات السابقة: ملحوظة: ليس ضروريا استخدام الدوال السهمية للاستفادة من ميزات ES6 الأخرى. function topThree (scores) { let [first, second, third] = scores return { first: first, second: second, third: third } } توجد طريقة بديلة لكتابة الدالة أعلاه وهي تفكيك المصفوفة أثناء تعريف الدالة. سنقلّل عدد الأسطُر في هذه الحالة كما أننا نعرف أن المعطى المُمرَّر لنا مصفوفة. function topThree ([first, second, third]) { return { first: first, second: second, third: third } } سنرى الآن تفصيلا صغيرا. بما أننا نستطيع الجمع بين المعاملات المبدئية والتفكيك أثناء تعريف الدوال.. فما هي نتيجة الشفرة التالية: function sayMyName ({ firstName = 'Zell', lastName = 'Liew' } = {}) { console.log(firstName + ' ' + lastName) } الأمر معقَّد قليل إذ أننا جمعنا ميزات عدّة في آن. أولا؛ نرى أن الدالة تأخذ معطى واحدا، وهو كائن اختياري تكون قميته {} عند عدم تحديد قيمة. ثانيًّا، نحاول تفكيك الكائن واستخراج المتغيرين firstName وlastName منه واستخدامهما إن وُجدا. أخيرا؛ عندما لا يُعيَّن المتغيران firstName وlastName في الكائن المُمرَّر فإننا نحدّد قيمتيهما بـ Zell وLiew على التوالي. تعطي الدالة النتائج التالية: sayMyName() // Zell Liew sayMyName({firstName: 'Zell'}) // Zell Liew sayMyName({firstName: 'Vincy', lastName: 'Zhang'}) // Vincy Zhang سنتعرّف في مقال لاحق على ميزات أخرى جديدة في الإصدار ES6. ترجمة - بتصرّف - للمقال Introduction to commonly used ES6 features لصاحبه Zell.