javascript شرح تحميل - إغلاق جافا سكريبت داخل حلقات - مثال عملي بسيط




15 Answers

حسنًا ، المشكلة هي أن المتغير i ، ضمن كل من وظائفك المجهولة ، مرتبط بنفس المتغير خارج الوظيفة.

الحل الكلاسيكي: الإغلاق

ما تريد القيام به هو ربط المتغير داخل كل دالة إلى قيمة منفصلة غير متغيرة خارج الدالة:

var funcs = [];

function createfunc(i) {
    return function() { console.log("My value: " + i); };
}

for (var i = 0; i < 3; i++) {
    funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

نظرًا لعدم وجود نطاق كتلة في JavaScript - نطاق الوظائف فقط - عن طريق التفاف إنشاء الدالة في وظيفة جديدة ، فإنك تتأكد من بقاء قيمة "i" كما تريد.

2015 الحل: forEach

من خلال توفر Array.prototype.forEach (عام 2015) على نطاق واسع نسبياً ، تجدر الإشارة إلى أنه في تلك الحالات التي تنطوي على التكرار بشكل أساسي على مجموعة من القيم ، يوفر .forEach() طريقة نظيفة وطبيعية للحصول على إغلاق مميز كل التكرار. وهذا يعني ، بافتراض أنك حصلت على نوع من الصفيف يحتوي على قيم (مراجع DOM ، كائنات ، أيا كان) ، والمشكلة تنشأ من إعداد معاودة الاتصال الخاصة بكل عنصر ، يمكنك القيام بذلك:

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

الفكرة هي أن كل استدعاء لوظيفة رد الاتصال المستخدمة مع حلقة .forEach سيكون إغلاقها الخاص. المعلمة التي تم تمريرها إلى ذلك المعالج هي عنصر الصفيف الخاص بهذه الخطوة المحددة للتكرار. إذا تم استخدامه في رد اتصال غير متزامن ، فلن يتصادم مع أي من عمليات الاسترجاعات الأخرى المحددة في خطوات أخرى للتكرار.

إذا كنت تعمل في jQuery ، تعطيك وظيفة $.each() قدرة مماثلة.

حل ES6: let

تم الآن بدء تشغيل ECMAScript 6 (ES6) ، وهو أحدث إصدار من JavaScript ، في العديد من المتصفحات وأنظمة الواجهة الخلفية دائمة الخضرة. هناك أيضًا متسللون مثل Babel سيقومون بتحويل ES6 إلى ES5 للسماح باستخدام الميزات الجديدة على الأنظمة القديمة.

يقدم ES6 كلمات رئيسية جديدة للدعايات والثوابت التي يتم تحديد نطاقها بشكل مختلف عن المتغيرات المستندة إلى var . على سبيل المثال ، في حلقة مع فهرس يستند إلى let ، سيكون لكل تكرار من خلال الحلقة قيمة جديدة من i حيث يتم تحديد نطاق كل قيمة داخل الحلقة ، بحيث تعمل شفرتك كما تتوقع. هناك العديد من الموارد ، ولكني أوصيك بإمكانية تحديد نطاق 2ality كمصدر كبير للمعلومات.

for (let i = 0; i < 3; i++) {
    funcs[i] = function() {
        console.log("My value: " + i);
    };
}

على الرغم من ذلك ، كن حذرا ، فإن IE9-IE11 و Edge قبل دعم Edge 14 يسمحان لك بالحصول على الخطأ أعلاه (لا يقوما بإنشاء كلمة i جديدة في كل مرة ، لذا فإن كل الوظائف المذكورة أعلاه سوف تسجل 3 كما لو كانت تستخدم var ). أيدج 14 أخيرا يحصل على حق.

في المتصفح

var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = function() {          // and store them in funcs
    console.log("My value: " + i); // each should log its value.
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

يخرج هذا:

قيمي: 3
قيمي: 3
قيمي: 3

في حين أنني أرغب في الإخراج:

قيمي: 0
قيمي: 1
قيمي: 2

تحدث نفس المشكلة عند حدوث تأخير في تشغيل الدالة باستخدام مستمعي الأحداث:

var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {          // let's create 3 functions
  buttons[i].addEventListener("click", function() { // as event listeners
    console.log("My value: " + i);                  // each should log its value.
  });
}
<button>0</button><br>
<button>1</button><br>
<button>2</button>

... أو رمز غير متزامن ، على سبيل المثال باستخدام Promises:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for(var i = 0; i < 3; i++){
  wait(i * 100).then(() => console.log(i)); // Log `i` as soon as each promise resolves.
}

ما هو الحل لهذه المشكلة الأساسية؟




طريقة أخرى لم يتم ذكرها بعد هي استخدام Function.prototype.bind

var funcs = {};
for (var i = 0; i < 3; i++) {
  funcs[i] = function(x) {
    console.log('My value: ' + x);
  }.bind(this, i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

تحديث

كما هو موضح بواسطةsquint وmekdev ، يمكنك الحصول على أداء أفضل عن طريق إنشاء الدالة خارج الحلقة أولاً ثم ربط النتائج داخل الحلقة.

function log(x) {
  console.log('My value: ' + x);
}

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = log.bind(this, i);
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}




تأخرت قليلاً في الحفلة ، لكنني كنت أستكشف هذه المسألة اليوم ولاحظت أن العديد من الإجابات لا تتناول بالكامل كيف تعالج جافا سكريبت النطاقات ، وهو ما يتلخص في جوهره.

وكما ذكر العديد من الأشخاص الآخرين ، فإن المشكلة تكمن في أن الدالة الداخلية تشير إلى متغير i ذاته. فلماذا لا نقوم فقط بإنشاء متغير محلي جديد كل عملية تكرار ، ولدينا مرجع الدالة الداخلية بدلاً من ذلك؟

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    var ilocal = i; //create a new local variable
    funcs[i] = function() {
        console.log("My value: " + ilocal); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

تماما كما كان من قبل ، حيث خرجت كل وظيفة داخلية عن القيمة الأخيرة التي تم تعيينها إلى i ، فإن كل دالة داخلية تقوم الآن بإخراج القيمة الأخيرة المخصصة ل ilocal . ولكن لا ينبغي أن يكون كل التكرار ilocal الخاصة؟

اتضح ، هذه هي القضية. كل التكرار يشترك في نفس النطاق ، لذلك كل التكرار بعد الأول هو مجرد الكتابة ilocal . من MDN :

مهم: لا يحتوي جافا سكريبت على نطاق الحظر. يتم تحديد المتغيرات التي يتم إدخالها مع كتلة إلى وظيفة أو نص يحتوي على ، وتأثيرات وضع لها تستمر خارج الكتلة نفسها. بمعنى آخر ، لا تقدم عبارات الحظر نطاقًا. على الرغم من أن الكتل "المستقلة" هي بناء صحيح ، إلا أنك لا تريد استخدام كتل مستقلة في جافا سكريبت ، لأنها لا تفعل ما تعتقد أنه يفعل ، إذا كنت تعتقد أنها تفعل مثل هذه الكتل في C أو Java.

تمت إعادة التأكيد للتأكيد:

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

يمكننا رؤية ذلك من خلال التحقق من ilocal قبل إعلانه في كل مرة:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
  console.log(ilocal);
  var ilocal = i;
}

هذا هو بالضبط السبب في أن هذا الخطأ صعب جدا. على الرغم من أنك تقوم بإعادة تحديد متغير ، لن تقوم Javascript بطرح خطأ ، ولن تقوم JSLint بطرح تحذير. هذا هو السبب أيضا في أن أفضل طريقة لحل هذا هو الاستفادة من الإغلاق ، والتي هي في الأساس فكرة أنه في جافا سكريبت ، وظائف داخلية الوصول إلى المتغيرات الخارجية لأن النطاقات الداخلية "أرفق" النطاقات الخارجية.

وهذا يعني أيضًا أن الدوال الداخلية "تمسك" بالمتغيرات الخارجية وتبقيها على قيد الحياة ، حتى إذا عادت الدالة الخارجية. للاستفادة من ذلك ، فإننا نقوم بإنشاء واستدعاء وظيفة مجمّع ilocal نطاق جديد تمامًا ، وإعلان ilocal في النطاق الجديد ، وإرجاع دالة داخلية تستخدم ilocal (مزيد من الشرح أدناه):

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() { //create a new scope using a wrapper function
        var ilocal = i; //capture i into a local var
        return function() { //return the inner function
            console.log("My value: " + ilocal);
        };
    })(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

إن إنشاء الوظيفة الداخلية داخل دالة المجمع يعطي الوظيفة الداخلية بيئة خاصة لا يمكنها الوصول إليها إلا "إغلاق". وهكذا ، في كل مرة نطلق عليها الدالة wrapper ، نقوم بإنشاء وظيفة داخلية جديدة مع بيئة منفصلة خاصة بها ، مما يضمن أن المتغيرات ilocal لا تصطدم ilocal فوق بعضها البعض. يعطي بعض التحسينات الطفيفة الإجابة النهائية التي قدمها العديد من مستخدمي SO الآخرين:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
    return function() { //return the inner function
        console.log("My value: " + ilocal);
    };
}

تحديث

مع تعميم ES6 الآن ، أصبح بإمكاننا الآن استخدام الكلمة الأساسية الجديدة let بإنشاء متغيرات النطاق المحظور:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
    funcs[i] = function() {
        console.log("My value: " + i); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
    funcs[j]();
}

انظروا كم هو سهل الآن! لمزيد من المعلومات ، راجع هذه الإجابة ، التي تستند معلوماتي إليها.




وهناك طريقة أخرى للقول بأن ذلك هو أن i في وظيفتك ملزم في وقت تنفيذ الوظيفة ، وليس وقت إنشاء الوظيفة.

عند إنشاء الإغلاق ، i هو مرجع للمتغير المحدد في النطاق الخارجي ، وليس نسخة منه كما كان عند إنشاء الإغلاق. سيتم تقييمه في وقت التنفيذ.

توفر معظم الإجابات الأخرى طرقًا للتغلب عليها من خلال إنشاء متغير آخر لا يغير القيمة بالنسبة لك.

ظننت أنني سأضيف تفسيرا للوضوح. للحصول على حل ، شخصيا ، سأذهب مع هارتو لأنها الطريقة الأكثر تميزا في شرح ذلك من الإجابات هنا. أي من التعليمات البرمجية المنشورة ستعمل ، لكنني سأختار مصنع إغلاق بسبب الحاجة إلى كتابة كومة من التعليقات لشرح سبب إعلان متغير جديد (Freddy و 1800) أو بناء الجملة الغريبة المضمنة (apphacker).




إليك تباينًا آخر للتقنية ، على غرار Bjorn's (apphacker) ، والذي يتيح لك تعيين قيمة المتغير داخل الدالة بدلاً من تمريرها كمعلمة ، والتي قد تكون أكثر وضوحًا في بعض الأحيان:

for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

لاحظ أن أياً تكن التقنية التي تستخدمها ، يصبح متغير index نوعًا من المتغير الثابت ، يرتبط بالنسخة التي تم إرجاعها للدالة الداخلية. أي ، يتم الحفاظ على التغييرات على قيمتها بين المكالمات. يمكن أن يكون سهل للغاية.




الحل الأكثر بساطة سيكون ،

بدلا من استخدام:

var funcs = [];
for(var i =0; i<3; i++){
    funcs[i] = function(){
        alert(i);
    }
}

for(var j =0; j<3; j++){
    funcs[j]();
}

التي تنبيهات "2" ، لمدة 3 مرات. هذا لأن الدالات المجهولة التي تم إنشاؤها في حلقة ، سهم نفس الإغلاق ، وفي هذا الإغلاق ، قيمة i هي نفسها. استخدم هذا لمنع إغلاق مشترك:

var funcs = [];
for(var new_i =0; new_i<3; new_i++){
    (function(i){
        funcs[i] = function(){
            alert(i);
        }
    })(new_i);
}

for(var j =0; j<3; j++){
    funcs[j]();
}

الفكرة وراء هذا هي ، تغليف الجسم بأكمله للحلقة مع IIFE (تعبير دالة IIFE فوراً) وتمرير new_i كمعلمة new_i كـ i . بما أن الوظيفة المجهولة يتم تنفيذها على الفور ، فإن القيمة i تختلف لكل وظيفة محددة داخل الدالة المجهولة.

يبدو أن هذا الحل يلائم أي مشكلة من هذا القبيل لأنه سيتطلب الحد الأدنى من التغييرات على الكود الأصلي الذي يعاني من هذه المشكلة. في الواقع ، هذا هو حسب التصميم ، لا ينبغي أن يكون مشكلة على الإطلاق!




المشكلة الرئيسية في الشفرة التي يعرضها البروتوكول الاختياري هي i لا أقرأ أبدا حتى الحلقة الثانية. للتدليل ، تخيل رؤية خطأ داخل الشفرة

funcs[i] = function() {            // and store them in funcs
    throw new Error("test");
    console.log("My value: " + i); // each should log its value.
};

الخطأ لا يحدث في الواقع حتى يتم تنفيذ funcs[someIndex] () . باستخدام هذا المنطق نفسه ، يجب أن يكون واضحًا أن قيمة i لا يتم جمعها حتى هذه النقطة أيضًا. بمجرد انتهاء الحلقة الأصلية ، فإن i++ يجلب i إلى قيمة 3 التي ينتج عنها الشرط i < 3 الفشل ونهاية الحلقة. عند هذه النقطة ، i هو 3 وهكذا عندما يتم استخدام funcs[someIndex]() ويتم funcs[someIndex]() ، فإنه 3 - في كل مرة.

لتجاوز هذا ، يجب عليك تقييم i كما هو مصادفة. لاحظ أن هذا قد حدث بالفعل في شكل funcs[i] (حيث يوجد 3 فهارس فريدة). هناك عدة طرق لالتقاط هذه القيمة. واحد هو تمريرها كمعلمة لدالة تظهر في عدة طرق هنا بالفعل.

خيار آخر هو بناء كائن وظيفة والتي سوف تكون قادرة على إغلاق أكثر من المتغير. يمكن أن يتحقق ذلك على هذا النحو

jsFiddle Demo

funcs[i] = new function() {   
    var closedVariable = i;
    return function(){
        console.log("My value: " + closedVariable); 
    };
};



تعمل وظائف جافا سكريبت "على الإغلاق" على النطاق الذي يمكنهم الوصول إليه عند الإعلان ، وتحتفظ بالوصول إلى هذا النطاق حتى عندما تتغير المتغيرات في ذلك النطاق.

var funcs = []

for (var i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

تغلق كل وظيفة في المجموعة أعلاه عبر النطاق العالمي (عالمي ، ببساطة لأن ذلك هو النطاق الذي تم الإعلان عنه).

في وقت لاحق يتم استدعاء هذه الوظائف تسجيل أحدث قيمة من i في النطاق العالمي. هذا هو السحر والإحباط للإغلاق.

"إغلاق وظائف جافا سكريبت عبر النطاق الذي تم الإعلان عنه فيه ، والاحتفاظ بالوصول إلى هذا النطاق حتى عند تغيير قيم المتغير داخل ذلك النطاق."

يؤدي استخدام let بدلاً من var حل ذلك عن طريق إنشاء نطاق جديد في كل مرة يتم فيها تشغيل الحلقة ، مما يؤدي إلى إنشاء نطاق منفصل لكل وظيفة لإغلاقها. تقنيات أخرى مختلفة تفعل الشيء نفسه مع وظائف إضافية.

var funcs = []

for (let i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

( let المتغيرات التي تحجب نطاقها بدلًا من الدالة scoped. يتم الإشارة إلى الكتل بواسطة أقواس معقوفة ، ولكن في حالة التكرار ، يتم اعتبار متغير التهيئة ، في حالتنا ، معلنة في الأقواس.)




مع ميزات جديدة من نطاق ES6 يتم إدارة نطاق المستوى:

var funcs = [];
for (let i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (let j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

يتم استبدال الرمز في سؤال OP letبدلا من var.




أولاً ، افهم ما الخطأ في هذا الرمز:

var funcs = [];
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

هنا عندما funcs[]تتم تهيئة الصفيف ، iيجري زيادة ، funcsيتم تهيئة funcالصفيف ويصبح حجم الصفيف 3 ، لذلك i = 3,. الآن عندما funcs[j]()يتم استدعاء ، فإنه يستخدم مرة أخرى المتغير i، الذي تم بالفعل زيادة إلى 3.

الآن لحل هذا ، لدينا العديد من الخيارات. فيما يلي اثنان منها:

  1. يمكننا التهيئة iمع letأو تهيئة متغير جديد indexمع letجعله متساويًا i. لذلك عندما يتم إجراء المكالمة ، indexسيتم استخدام نطاقها بعد التهيئة. وللدعوة ، indexسيتم التهيئة مرة أخرى:

    var funcs = [];
    for (var i = 0; i < 3; i++) {          
        let index = i;
        funcs[i] = function() {            
            console.log("My value: " + index); 
        };
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
    
  2. يمكن أن يكون الخيار الآخر هو تقديم tempFuncالدالة الفعلية التالية:

    var funcs = [];
    function tempFunc(i){
        return function(){
            console.log("My value: " + i);
        };
    }
    for (var i = 0; i < 3; i++) {  
        funcs[i] = tempFunc(i);                                     
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
    



ونحن سوف تحقق، ما يحدث فعلا عندما تقوم بتعريف varو letاحدا تلو الآخر.

الحالة 1 : استخدامvar

<script>
   var funcs = [];
   for (var i = 0; i < 3; i++) {
     funcs[i] = function () {
        debugger;
        console.log("My value: " + i);
     };
   }
   console.log(funcs);
</script>

الآن افتح نافذة وحدة التحكم في Chrome بالضغط على F12 وتحديث الصفحة. قم بإنفاق كل 3 وظائف داخل الصفيف. سترى خاصية تسمى [[Scopes]].Expand ذلك. سترى كائن صفيف واحد يسمى "Global"، وتوسيع هذا واحد. ستجد خاصية 'i'معلنة في الكائن ذي القيمة 3.

استنتاج:

  1. عندما تقوم بتعريف متغير باستخدام 'var'خارج وظيفة ، يصبح المتغير الشامل (يمكنك التحقق من خلال الكتابة iأو window.iفي نافذة وحدة التحكم. وسوف يعود 3).
  2. ﻟﻦ ﺗﺘﺼﻞ اﻟﻮﻇﻴﻔﺔ اﻟﻤﺬآﻮرة اﻟﺘﻲ ﻗﻤﺖ ﺑﺈﻋﻼﻧﻬﺎ ﺑﺎﻟﺘﺤﻘﻖ ﻣﻦ اﻟﻘﻴﻤﺔ داﺧﻞ اﻟﻮﻇﻴﻔﺔ واﻟﺘﺤﻘﻖ ﻣﻨﻬﺎ إﻻ إذا اﺳﺘﺪﻋﺖ اﻟﻮﻇﺎﺋﻒ
  3. عند استدعاء الدالة ، console.log("My value: " + i)تأخذ القيمة من Globalالكائن الخاص بها وتعرض النتيجة.

CASE2: استخدام السماح

الآن استبدال 'var'مع'let'

<script>
    var funcs = [];
    for (let i = 0; i < 3; i++) {
        funcs[i] = function () {
           debugger;
           console.log("My value: " + i);
        };
    }
    console.log(funcs);
</script>

افعل نفس الشيء ، اذهب إلى النطاقات. الآن سترى كائنين "Block"و "Global". الآن قم بتوسيع Blockالكائن ، سترى 'i' معرّفة هناك ، والشيء الغريب هو أنه ، لكل وظيفة ، القيمة إذا كانت iمختلفة (0 ، 1 ، 2).

استنتاج:

عندما تقوم بتعريف متغير باستخدام 'let'حتى خارج الوظيفة ولكن داخل الحلقة ، لن يكون هذا المتغير متغيرًا عالميًا ، سيصبح Blockمتغير مستوى متاح فقط لنفس الوظيفة فقط. هذا هو السبب ، نحن نحصل على قيمة iمختلفة لكل وظيفة عندما نستدعي الوظائف.

لمزيد من التفاصيل حول كيفية عمل أقرب ، يرجى الدخول من خلال البرنامج التعليمي الفيديو الرائع https://youtu.be/71AtaJpJHw0




استخدام هيكل closure ، وهذا من شأنه أن يقلل من حلقة إضافية. يمكنك القيام بذلك في حلقة واحدة للحلقة:

var funcs = [];
for (var i = 0; i < 3; i++) {     
  (funcs[i] = function() {         
    console.log("My value: " + i); 
  })(i);
}



يمكنك استخدام وحدة تعريفية لقوائم البيانات مثل query-js (*). في هذه الحالات ، أجد شخصياً أسلوباً إعلانياً أقل غرابة

var funcs = Query.range(0,3).each(function(i){
     return  function() {
        console.log("My value: " + i);
    };
});

يمكنك بعد ذلك استخدام الحلقة الثانية والحصول على النتيجة المتوقعة أو يمكنك القيام بها

funcs.iterate(function(f){ f(); });

(*) أنا مؤلف استقصاء js و لذلك متحيز لاستخدامه ، لذلك لا تأخذ كلماتي كتوصية للمكتبة المذكورة فقط للنهج الإعلاني :)




تبدو العديد من الحلول صحيحة ولكنها لا تذكر أنها تسمى Curryingنمط تصميم برمجة وظيفي لحالات مثل هنا. 3-10 مرات أسرع من الربط حسب المتصفح.

var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = curryShowValue(i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

function curryShowValue(i) {
  return function showValue() {
    console.log("My value: " + i);
  }
}

شاهد كسب الأداء في المتصفحات المختلفة .




var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = function(param) {          // and store them in funcs
    console.log("My value: " + param); // each should log its value.
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j](j);                      // and now let's run each one to see with j
}



Related