Function.prototype.bind()‎

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

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

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

fun.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg

وسيطٌ يُمثِّل قيمة المعامل this التي ستُستعمل في الدالة func عند استدعائها، لاحظ أنَّ JavaScript ستتجاهل هذه القيمة إذا استدعيت الدالة كدالة بانية باستخدام المعامل new.

arg1, arg2, ...‎

الوسائط التي ستُرفَق مع الوسائط المُمرَّرة إلى الدالة عند استدعائها.

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

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

الوصف

الدالة bind()‎ تُنشِئ ما يسمى bound function (اختصارًا BF)، و BF هي exotic function object (هذه المصطلحات مأخوذة من معيار ECMAScript 2015 وآثرنا ذكرها كما هي) التي تغلِّف (wraps) كائن الدالة الأصلي.

استدعاء BF يؤدي إلى استدعاء الدالة المُغلَّفة. وتملك BF الخاصيات الداخلية الآتية:

  • [[BoundTargetFunction]]: كائن الدالة المُغلَّف.
  • [[BoundThis]]: القيمة التي تُمرَّر كقيمة المعامل this عند استخدام الدالة المُغلَّفة.
  • [[BoundArguments]]: قائمة بالقيم التي ستُمرَّر كأوّل وسائط لأيّ استدعاء للدالة المُغلَّفة.
  • [[Call]]: تنفيذ الشيفرة المرتبطة بالكائن.

عند استدعاء bound function، فستستدعي الدالة الداخلية [[Call]] على [[BoundTargetFunction]]، مع الوسائط الآتية Call(boundThis, args)‎، إذ إنَّ قيمة boundThis هي [[BoundThis]] و args هي [[BoundArguments]] متبوعةً بالوسائط المُمرَّرة إلى الدالة التي جرى استدعاؤها.

أمثلة

إنشاء bound function

أبسط استخدام للدالة bind هي إنشاء دالة التي ستُستخدَم فيها قيمة this معيّنة بغض النظر عن كيفية استدعائها.

خطأٌ شائعٌ يرتكبه مبرمجو JavaScript الجدد هو استخراج دالة من كائن، ثم استدعاء تلك الدالة لاحقًا مع توقع أنَّ تلك الدالة ستستخدم الكائن الأصلي كقيمة للمعامل this؛ لكن ما لم نتخذ إجراءات معيّنة، فإنَّ الكائن الأصلي لن يعود مرتبطًا بالدالة. إنشاء bound function من تلك الدالة -التي تستخدم الكائن الأصلي- سيحلّ تلك المشكلة:

this.x = 9;    // يشير المعامل this إلى الكائن العام
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX(); // 9   
// ستستدعى الدالة في المجال العام

// إنشاء دالة جديدة مرتبطة بالكائن
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

توفير قائمة وسائط مبدئية

استخدامٌ بسيطٌ آخر للدالة bind هو إنشاء دوال لها وسائط مُعرَّفة مسبقًا؛ فتلك الوسائط ستأتي بعد قيمة this عند تعريف الدالة، وستُمرَّر إلى الدالة الهدف في أوّل قائمة الوسائط، وتتبعها الوسائط الأخرى التي تُحدَّد عند الاستدعاء:

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// إنشاء دالة لها وسيطٌ يُمرَّر دومًا كأوّل وسيط ويليه الوسائط الأخرى
var leadingThirtysevenList = list.bind(null, 37);

var list2 = leadingThirtysevenList(); 
// [37]

var list3 = leadingThirtysevenList(1, 2, 3);
// [37, 1, 2, 3]

استخدامها مع الدالة setTimeout

عند استخدام الدالة window.setTimeout()‎ ستُضبَط الكلمة المحجوزة this إلى الكائن العام window، فعند التعامل مع الدوال التابعة لكائنات التي تتطلب أن تشير this إلى الكائن، فيمكنك استخدام الدالة bind()‎ لربط this إلى الدالة المستدعاة كما في المثال الآتي:

function LateBloomer() {
  this.petalCount = Math.floor(Math.random() * 12) + 1;
}

LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();

إنشاء اختصارات

تفيد الدالة bind()‎ في الحالات التي نريد إنشاء اختصار إلى دالة التي تتطلب قيمة this مُحدَّدة.

لنأخذ الدالة Array.prototype.slice مثالًا، التي يمكنك استخدامها لتحويل كائن شبيه بالمصفوفات إلى مصفوفة حقيقة. يمكنك إنشاء اختصار كما يلي:

var slice = Array.prototype.slice;

// ...

slice.apply(arguments);

لكن مع استخدام الدالة bind()‎ نستطيع تبسيط ما سبق، ففي الشيفرة الآتية ترتبط slice بالدالة Function.prototype.apply()‎، وستُضبَط قيمة this إلى الدالة Array.prototype.slice()‎، وهذا يعني أنَّه لا حاجة إلى إضافة استدعاءات apply()‎ إضافية:

var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.apply.bind(unboundSlice);

// ...

slice(arguments);

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

الميزة Chrome Firefox Internet Explorer Opera Safari
الدعم الأساسي 7 4 9 11.6 5.1

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