introduction to es6 الميزات الجديدة في ES6: المعاملات المبدئية والتفكيك Destructuring


محمد أحمد العيل

تعرّفنا في مقال سابق على ميزات جديدة في الإصدار 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.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن