السلام عليكم و رحمه الله تعالى و بركاته
ال closure هو امكانيه وظيفه داخليه ان تشير إلى متغيرات الوظيفه الخارجيه التى تحتويها بعد انتهاء تنفيذ الوظيفه الخارجيه – اقرأها اكثر من مره ، قد اشرت فى هذا الموضوع إلى ال currying و ماهى إلى تطبيق من تطبيقات ال closure ، و اليك المثال البسيط التالى الذى يوضح ال closure فى ابسط صوره :
function add(x){
return function(y){
return x + y ;
};
};
var add5 = add(5);
alert(add5(3)); //8
قمت بعمل وظيفه بإسم add و تقبل عباره واحده بإسم x ، هذه الوظيفه تقوم بإرجاع وظيفه داخلها ، مع ملاحظه ان x التى فى ال وظيفه الداخليه تأخذ قيمتها من x التى تمرر للوظيفه add .
عند استدعاء الوظيفه add و اعطاءها العباره 5 فإن الوظيفه الداخليه يتم ملىء المتغير x بالقيمه 5 ، , و يتم ارجاع هذه الوظيفه عن طريق return ، لذلك فإن الوظيفه الناتجه add5 تتحول للتالى :
function add5(y){
return 5 + y
}
add5(3); // 8
و لذلك النتيجه الطبيعيه للوظيفه add5 و اعطائها العباره 3 تكون 8 كما يوضح السطر الاخير فى الكود السابق .
ال closure يحل مشكله هامه جدا ، تسجيل الاحداث ديناميكا ، كما يوضح الكود التالى الذى يقوم بإنشاء خمس لينكات داخل بيئه المتصفح و عند الضغط على كل لينك فإنه يعطيه رقم من واحد إلى خمسه بترتيب إنشائهم :
function makeLinks(){
var arr = [1,2,3,4,5];
for(var i=0; i<arr.length; i+=1){
var link = document.createElement("a");
link.innerHTML = "link"+i;
document.body.appendChild(link);
link.onclick = function(){
alert(i);
}
}
}
يتم إنشاء خمس لينكات ، كل لينك ياخذ نص ديناميكى بناء على ترتيب انشاءه مثل link1 ، link2 … الخ ، لكن عند الضغط على اى لينك منهم فإن الناتج 5
، ما المشكله ؟؟ إذا رجعت لتعريف ال closure فى اول الموضوع ستجد ان الوظيفه الداخليه تستطيع الوصول لمتغيرات الوظيفه الخارجيه فقط بعد انتهاء تنفيذ الخارجيه ، و لو نظرت للكود السابق ستجد انه هناك وظيفه واحده خارجيه و خمس وظائف داخليه ، لذلك المتغير arr يمكن الوصول اليه فقط عند انتهاء تنفيذ الخارجيه و فى هذه الحاله يصل المتغير إلى القيمه 5 ، يعنى يوجد closure واحد فقط ، اذا ما الحل ؟ الحل فى استخدام self invoking anonymous function حول الوظيفه التى تستمع للحدث لتوليد closure جديد كما يوضح الكود البسيط التالى :
function makeLinks(){
var arr = [1,2,3,4,5];
for(var i=0; i<arr.length; i+=1){
var link = document.createElement("a");
link.innerHTML = "link"+i;
document.body.appendChild(link);
link.onclick = function(num){ // new closure
return function() {
alert(num);
}
}(i); // execute the outer function
}
}
عند تجربه الكود السابق فستجد انه يعمل 100% و كل لينك سيعمل alert بالرقم الذى يمثله ، قمت بإنشاء وظيفه جديده يتم تنفيذها تلقائيا – لاحظ (i) التى بجوار { – حول الوظيفه التى تستمع للحدث و يتم تسجيلها ل onclick و بذلك قمت بإنشاء closure جديد حول كل وظيفه داخليه و بذلك ستتمكن من متابعه قيمه المتغير arr ، اكيد الموضوع مش سهل انه يتفهم من اول مره .
للمزيد :
explaining JS scope and closure
JS Closure
تم اضافه هذا الموضوع لقائمه دروس سلسله oop js لاهميته .
الأوسمة: javascript, oop
28/01/2009 عند 8:27 م |
يقال أن الFucntios في جافاسكربت هن مواطنات من الدرجة الأولى
، فعلاً!
، يحتاج لقراءة متأنية! أتوقع لأنني لم أحتج يوماً لعمل هذا
(جديد على الجافاسكربت)
لكن موضوعك مربك
28/01/2009 عند 9:17 م |
نعم يا عمر in javascript function is first class ، و تؤثر على ال scope و ال context ، هذه الموضوع ستؤثر غالبا على عمل ال api لاطر عمل الجافاسكربت ، فلذلك لابد من شرحها و فهمها ان كنت تريد ان تكون محترف JS
30/01/2009 عند 8:11 ص |
صحيح كما ذكر الاخ عمر بانه شوي مربك بصراحة انا قرئته عدمة مرات تااستطعت استيعاب الفكرة
من وؤاء ارجع وظيفية بدك قيمة في المثال الاول
function add(x){
return function(y){
return x + y ;
};
};
var add5 = add(5);
alert(add5(3)); //8
لو تلاحظ انه انشاء متغير واحطاه القيمة وهيا دالة وبما انه الدالة اعطاها قيمة تعود بدالة فاصبح بامكانه تشغيل هذه الدالة مرة اخرى فالظاهر يخدع ولكن الفكرة قوية
var e=e();
e(20);
شكرا جزيلا للجميع وبخاصة كاتب المقالة ودمتم سالمين
30/01/2009 عند 8:18 ص |
الفكرة بسيطة اذا امعنت النظر هيا انشاء دالة تعيد قيمة لدالة مثال باسلوب المتغيرات
var e=function(x){
return function(t){
alert(x+t);
}
}
var t=e(2);
t(10);
بما اننا انشائنا متغير واعطيناه قيمة وبما ان القيمة تساوي دالة فيمكن استدعاء الدالة
وهذا المثال يندرج تحت مفهوم صفوف التأشير الذاتي
اي
x=*x
اشارة الضرب هيا مؤشر الى نفس الاجراء شكرا لصاحب المقالة ولاخ عمر وبراك الله فيكم وان اشء الله الى الامام
30/01/2009 عند 8:19 ص |
شكرا جزيلا