Function.prototype.apply()‎

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

الدالة Function.prototype.apply()‎ تستدعي دالةً وتضبط قيمة this فيها إلى القيمة المعطية، وستُوفَّر الوسائط التي ستُمرَّر إليها كمصفوفة (أو كائن شبيه بالمصفوفات).

ملاحظة: صحيحٌ أنَّ البنية العامة لهذه الدالة تكاد تماثل بينة الدالة call()‎، لكن الفرق الرئيسي بينهما هو أنَّ الدالة call()‎ تقبل قائمةً بالوسائط التي تُمرَّر إلى الدالة، بينما apply()‎ تقبل مصفوفةً واحدةً تحتوي على الوسائط.

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

func.apply([thisArg, argsArray])

thisArg

وسيطٌ اختياري، وهو يُمثِّل قيمة المعامل this التي ستُستعمل في الدالة func، لاحظ أنَّ قيمة this المُمرَّرة لا تعني بالضرورة أنَّها القيمة التي ستستخدمها الدالة؛ فلو لم يكن تنفيذ الدالة في نمط strict، فسيُستعاض عن القيمتين null و undefined بالكائن العام (global object)، وستُغلَّف القيم الأوليّة بكائنات.

argsArray

وسيطٌ اختياري، وهو مصفوفة أو كائن شبيه بالمصفوفات، يُحدِّد ما هي الوسائط التي ستُمرَّر إلى الدالة func، ويمكن أن تكون قيمة هذا الوسيط هي null أو undefined إذا لم تكن هنالك وسائط يجب تمريرها إلى الدالة.

القيمة المعادة

القيمة المعادة نتيجة استدعاء الدالة المُحدَّدة مع قيمة this والوسائط (إن وُجِدَت).

الوصف

يمكنك إسناد قيمة this مختلفة عند استدعاء دالة موجودة مسبقًا؛ إذ يُشير المعامل this إلى الكائن الحالي؛ أما عند استخدام apply، فيمكننا كتابة دالة مرةً واحدةً ثم استدعاؤها في كائنٍ آخر، دون الحاجة إلى إعادة كتابة تلك الدالة في الكائن الجديد.

الدالة apply()‎ شبيهة جدًا بالدالة call()‎، باستثناء نوع الوسائط التي تدعمه كلُّ واحدةٍ منهما. فيمكننا استخدام مصفوفة من الوسائط بدلًا من قائمة بها، فعند استخدام الدالة apply()‎ نستطيع استخدام مصفوفة مُنشَأة بالشكل المختصرة كما في func.apply(this, ['eat', 'bananas'])‎ أو كائن Array كما في func.apply(this, new Array('eat', 'bananas'))‎.

يمكنك أيضًا استخدام الكائن arguments في المعامل argsArray، إذ إنَّ الكائن arguments هو متغيرٌ محليٌ موجودٌ ضمن الدوال، ويمكن استخدامه لتمرير جميع الوسائط المُمرَّرة إلى الكائن الذي سيستدعي الدالة. وبالتالي لا يُفترَض أن تعرف عدد الوسائط عند استخدام الدالة apply.

وبدءًا من معيار ECMAScript 5.1 يمكننا استخدام أي كائن يشبه المصفوفات، مما يعني أنَّ سيملك الخاصية length وتكون أسماء الخاصيات فيه أعدادًا صحيحةً تقع في المجال ‎(0...length-1)‎. فمثلًا يمكن استخدام الكائن الآتي: ‎{ 'length': 2, '0': 'eat', '1': 'bananas' }‎.

أمثلة

استخدام الدالة apply مع الدوال البانية

يمكننا استخدام apply لإنشاء سلسلة من الدوال البانية (chain of constructors) لأحد الكائنات بما يشبه لغة Java، ففي المثال الآتي سنُنشِئ دالةً تتبع إلى الكائن Function باسم construct، وستسمح لنا هذه الدالة بتمرير كائن يشبه المصفوفات إلى الدوال البانية بدلًا من قائمة بالوسائط:

Function.prototype.construct = function(aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

مثال عن استخدام الدالة construct السابقة:

function MyConstructor() {
  for (var nProp = 0; nProp < arguments.length; nProp++) {
    this['property' + nProp] = arguments[nProp];
  }
}

var myArray = [4, 'Hello world!', false];
var myInstance = MyConstructor.construct(myArray);

console.log(myInstance.property1);                // 'Hello world!'
console.log(myInstance instanceof MyConstructor); // 'true'
console.log(myInstance.constructor);              // 'MyConstructor'

استخدام apply مع الدوال المُضمَّنة في اللغة

يُسهِّل التوظيف الذكي للدالة apply من استخدام الدوال المُضمَّنة في اللغة في بعض المهام، وتلك المهام كانت تتطلب كتابة حلقة تكرار للمرور على عناصر المصفوفة.

سنستخدم في المثال الآتي الدالة Math.max و Math.min معرفة أكبر وأصغر قيمة في مصفوفة:

// معرفة أكبر وأصغر قيمة في المصفوفة الآتية
var numbers = [5, 6, 2, 3, 7];

// استخدام الدالة apply
var max = Math.max.apply(null, numbers); 
// وهذا يكافئ
// Math.max(numbers[0], ...)
// Math.max(5, 6, ...)

var min = Math.min.apply(null, numbers);

// استخدام حلقة تكرار تقليدية
max = -Infinity, min = +Infinity;

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] > max) {
    max = numbers[i];
  }
  if (numbers[i] < min) {
    min = numbers[i];
  }
}

لكن اعلم أنَّ استخدامك للدالة apply بهذه الطريقة يُعرِّضك لتجاوز الحد الأقصى لعدد الوسائط المُمرَّرة إلى دالةٍ ما في محرِّك JavaScript (الرقم الدقيق للعدد الأقصى للوسائط يختلف من محرّك إلى آخر، فمحرِّك JavaScriptCore يسمح بتمرير 65536 وسيطًا)، وعند تمرير وسائط عددها أكبر من الحد الأقصى الذي يقبله محرّك JavaScript فسترمي بعض المحركات استثناءً، لكن غيرها ستتجاهل الوسائط الزائدة.

فإذا افتراضنا أنَّ الحد الأقصى لعدد الوسائط في أحد المحركات هو أربعة وسائط (بالطبع يكون الحد الأقصى أكثر من ذلك بكثير)، فستكون الوسائط المُمرَّرة إلى الدالة في المثال السابق هي ‎5, 6, 2, 3 بدلًا من المصفوفة كاملةً.

إذا كانت المصفوفة التي ستُمرِّرها إلى الدالة كبيرة جدًا (بضعة آلاف من القيم)، فحاول تقسيمها إلى أقسام وتطبيق الدالة على تلك الأقسام:

function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null, 
                                arr.slice(i, Math.min(i+QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);

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

الميزة Chrome Firefox Internet Explorer Opera Safari
الدعم الأساسي نعم نعم نعم نعم نعم

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