سؤال

من: http://ejohn.org/apps/learn/#2

Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

هل يمكن لأي شخص أن يخبرني لماذا العائد الثاني ضروري (قبل fn.apply)؟

أيضا ، هل يمكن لأي شخص أن يشرح لماذا يكون Args.Concat ضروريًا؟ لماذا لا يتم إعادة كتابتها على النحو التالي:

fn.apply(object, args)

بدلاً من

return fn.apply(object,
          args.concat(Array.prototype.slice.call(arguments)));
هل كانت مفيدة؟

المحلول

الإرجاع الثاني ضروري لأننا سنفقد أي قيمة إرجاع من وظيفة Bound.

قد تعرف هذا بالفعل ، لكن لا يضر بالذكر. إذا لم نلتف fn.apply داخل وظيفة أخرى ، ثم ننادي الوظيفة مباشرة fn وهو دون المستوى الأمثل ، مثل bind من المفترض فقط تعيين سياق التنفيذ (ما ينبغي this الرجوع إلى داخل الوظيفة) ، ولا تستدعيها.

يمكن استدعاء طرق JavaScript عن طريق الاتصال call أو apply طريقة عليهم. هذا مثال صغير:

function example() {
    alert("useless example");
}

example.apply() // or example.call(), alerts "useless example";

من المفترض أن تعمل الوظيفة الخارجية في BIND () النموذج الأولي () مثل غلاف غير مرئي حول الوظيفة المربوطة. وبالتالي ، يجب تمرير أي وسيطات يتم تمريرها إلى الغلاف إلى الوظيفة المربوطة أيضًا ، ويجب أن تُرجع أي قيمة تعود الوظيفة المرتبطة ، وهذا هو السبب في وجود عبارة الإرجاع.

سبب القيام args.concat داخل fn.apply مختلف وهو ليس اختياريًا. bind في النموذج الأولي ، يتيح لك تقديم الوسيطات إلى الوظيفة المربوطة.

args يمثل الحجج التي تم تمريرها عندما اتصلنا bind على الوظيفة. arguments يمثل الحجج التي تم تمريرها عندما أطلقنا على الوظيفة المربوطة. نحن في الأساس تسلسل صفيفتين هناك.

من المثال أعلاه:

var obj = { x: 'prop x' };
var boundExample = example.bind(obj, 12, 23); // args => 12, 23
boundExample(36, 49); // arguments => 36, 49

// arguments that our example() function receives => 12, 23, 36, 49

نصائح أخرى

بوست القديمة ولكن نهج أحدث ؛)

Function.prototype.bind = function(){
    var fn = this, 
    context = arguments[0], 
    args = Array.prototype.slice.call(arguments, 1);
    return function(){
        return fn.apply(context, args.concat([].slice.call(arguments)));
    }
}

obj = {'abc':'x'};
var func = function() {
  console.log(arguments);
  alert(this.abc);
}
var x = func.bind(obj);

console.log(x(1,2,3));

هذا مثال جيد جدًا لشرحه. قم بتشغيله وتحقق من سجل وحدة التحكم. ثم قم بتعديل الكود للتغاضى

[].slice.call(arguments)

سترى أن Console.log لتنفيذ X (1،2،3) لم يعد يظهر الحجج. وذلك لأن كائنات الوسائط هي متغير محلي داخل جميع الوظائف. قد يبدو هذا مربكًا بعض الشيء ، لكن ما يعنيه هو بشكل أساسي:

var x = func.bind(obj,1,2,3);

إرجاع هذه الوظيفة داخليًا:

function() {
    return fn.apply(obj, [1,2,3].concat([].slice.call(arguments)));
}

لذلك هو أكثر من قالب للوظيفة.

عندما تقوم الآن بتشغيله مثل:

x(4,5,6)

سيتم تشغيل هذا:

fn.apply(obj, [1,2,3].concat([].slice.call(arguments)))

مع كائن وسيطات خاصة = {0: 4،1: 5،2: 6} ، والتي يمكن تحويلها إلى صفيف باستخدام [] الوظيفة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top