معامل النشر Spread في JavaScript

من موسوعة حسوب

معامل النشر (spread operator) يسمح للكائنات التي يمكن المرور على عناصرها -مثل تعابير المصفوفات أو السلاسل النصية (أي أنها iterable)- أن توسَّع في الأماكن التي تتوقع JavaScript وجود صفر وسيط أو أكثر (عند استدعاء الدوال) أو صفر عنصر أو أكثر (في المصفوفات)، أو نشر كائن في الأماكن التي تتوقع JavaScript وجود صفر زوج أو أكثر من المفاتيح والقيم المرتبطة بها (عند تعريف الكائنات).

البنية العامة

عند استدعاء الدوال:

myFunction(...iterableObj);

في المصفوفات أو السلاسل النصية:

[...iterableObj, '4', 'five', 6];

عند تعريف الكائنات (ميزة جديدة في EMCAScript، انظر قسم «مصادر ومواصفات»):

let objClone = { ...obj };

أمثلة

استخدام معامل النشر عند استدعاء الدوال

الاستغناء عن استخدام الدالة apply

من الشائع استخدام الدالة Function.prototype.apply في الحالات حيث تريد استخدام عناصر مصفوفة ما كوسائط لتمريرها إلى دالة:

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);

أما عند استخدام معامل النشر، فيمكن أن تُكتَب الشيفرة السابقة كما يلي:

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);

لاحظ أنَّ بالإمكان استخدام معامل النشر مكان أيّ وسيط من قائمة الوسائط، ويمكن أن يُكرَّر استخدامه عدِّة مرات:

function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);

استخدام معامل النشر عند استدعاء الدوال البانية

عند استدعاء دالة بانية باستخدام المعامل new فمن غير الممكن استخدام مصفوفة والدالة apply مباشرةً (إذ إنَّ الدالة apply تجري عملية استدعاء [[Call]] وليس بناء [[Construct]])، لكن يمكن استخدام مصفوفة مع دالة بانية بسهولة عبر معامل النشر:

var dateFields = [1970, 0, 1];  // 1 Jan 1970
var d = new Date(...dateFields);

أما لاستخدام مصفوفة كمعاملات لدالة بانية دون استخدام معامل النشر، فيمكنك فعل ذلك بطريقة غير مباشرة كما في المثال الآتي:

function applyAndNew(constructor, args) {
   function partial () {
      return constructor.apply(this, args);
   };
   if (typeof constructor.prototype === "object") {
      partial.prototype = Object.create(constructor.prototype);
   }
   return partial;
}


function myConstructor () {
   console.log("arguments.length: " + arguments.length);
   console.log(arguments);
   this.prop1="val1";
   this.prop2="val2";
};

var myArguments = ["hi", "how", "are", "you", "mr", null];
var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);

console.log(new myConstructorWithArguments);
// (internal log of myConstructor):           arguments.length: 6
// (internal log of myConstructor):           ["hi", "how", "are", "you", "mr", null]
// (log of "new myConstructorWithArguments"): {prop1: "val1", prop2: "val2"}

استخدام معامل النشر مع المصفوفات

استفادة قصوى من الشكل المختصر لتعريف المصفوفات

دون استخدام معامل النشر، لن نتمكن من استخدام الشكل المختصرة لتعريف مصفوفة جديدة تستخدم مصفوفةً أخرى كجزء منها، وسيصبح استخدام شيفرة مطوّلة أمرٌ لا بدّ منه ويجب استخدام مجموعة من دوال push و splice و concat ...إلخ. لكن عند استخدام معامل النشر فسيصير شكل تعريف المصفوفة أقصر بكثير:

var parts = ['shoulders', 'knees']; 
var lyrics = ['head', ...parts, 'and', 'toes']; 
// ["head", "shoulders", "knees", "and", "toes"]

وكما عند استخدام معامل النشر في قائمة وسائط الدالة، يمكن استخدام المعامل ... في أيّ مكان في الشكل المختصر لتعريف المصفوفات ويمكن تكراره أكثر من مرة.

نسخ مصفوفة

لاحظ كيف سيؤدي استخدام معامل النشر إلى نسخ محتويات المصفوفة arr إلى arr2، وعند تغيير المصفوفة arr2 فلن تتأثر المصفوفة الأصلية arr:

var arr = [1, 2, 3];
var arr2 = [...arr];
arr2.push(4); 

// arr2 [1, 2, 3, 4]
// arr ستبقى على حالها

لاحظ أنَّ معامل النشر لن ينسخ إلا مستوى واحد من المصفوفات، أي أنَّه ليس مناسبًا لنسخ المصفوفات متعددة الأبعاد كما يبيّن المثال الآتي، الذي سيتتأثر فيه المصفوفة a عند تغيير المصفوفة b:

var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// a: [[], [2], [3]]

طريقة أفضل لجمع المصفوفات لبعضها بعضًا

تُستخدَم الدالة concat عادةً لإضافة مصفوفة ما إلى نهاية مصفوفة أخرى، ويمكن فعل ذلك دون معامل النشر كما في المثال الآتي الذي أضفنا فيه جميع عناصر المصفوفة arr2 إلى نهاية المصفوفة arr1:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];

arr1 = arr1.concat(arr2);

يمكننا فعل ذلك باستخدام معامل النشر:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];

arr1 = [...arr1, ...arr2];

تُستخدَم الدالة unshift عادةً لإضافة قيم مصفوفة ما إلى بداية مصفوفة أخرى:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];

Array.prototype.unshift.apply(arr1, arr2) // arr1: [3, 4, 5, 0, 1, 2]

أما مع استخدام معامل النشر، فسيُبسَّط المثال السابق كثيرًا:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];

arr1 = [...arr2, ...arr1]; // arr1: [3, 4, 5, 0, 1, 2]

استخدام معامل النشر مع الكائنات

أضاف اقتراح Rest/Spread Properties for ECMAScript استخدام معامل النشر عند تعريف الكائنات، حيث سينسخ الخاصيات القابلة للإحصاء (enumerable properties) من أحد الكائنات إلى الكائن الآخر.

أصبح بإمكاننا القيام بعملية النسخ السطحي (shallow cloning، أي باستثناء كائن prototype) أو دمج كائنين بطريقة أقصر من استخدام الدالة Object.assign()‎:

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };

var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }

يُستخدَم معامل النشر لكائنات iterable فقط

لا يمكن أن يُطبَّق معامل النشر إلى على كائنات iterable فقط (باستثناء عملية نشر كائن ضمن كائن آخر):

var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable

معامل النشر مع قيم كثيرة

عند استخدام معامل النشر عند استدعاء الدوال، فضع في ذهنك إمكانية تجاوز العدد الأقصى للوسائط في محرِّك JavaScript؛ راجع صفحة الدالة apply لمزيدٍ من التفاصيل.

دعم المتصفحات

الميزة Chrome Firefox Internet Explorer Opera Safari
الدعم في المصفوفات 46 16 غير مدعومة 37 8
الدعم في الدوال 46 27 غير مدعومة 37 8
الدعم في الكائنات 60 55 غير مدعومة ؟ غير مدعومة

على النقيض من متصفح IE، يدعم متصفح Edge معامل النشر في المصفوفات والدوال.

مصادر ومواصفات