ال closure فى جافاسكربت


السلام عليكم و رحمه الله تعالى و بركاته

ال 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 لاهميته .

الأوسمة: ,

7 تعليقات to “ال closure فى جافاسكربت”

  1. Omar Al-Dolaimy Says:

    يقال أن الFucntios في جافاسكربت هن مواطنات من الدرجة الأولى :)، فعلاً!
    لكن موضوعك مربك :)، يحتاج لقراءة متأنية! أتوقع لأنني لم أحتج يوماً لعمل هذا🙂 (جديد على الجافاسكربت)

  2. mostafa farghaly Says:

    نعم يا عمر in javascript function is first class ، و تؤثر على ال scope و ال context ، هذه الموضوع ستؤثر غالبا على عمل ال api لاطر عمل الجافاسكربت ، فلذلك لابد من شرحها و فهمها ان كنت تريد ان تكون محترف JS

  3. almhajer Says:

    صحيح كما ذكر الاخ عمر بانه شوي مربك بصراحة انا قرئته عدمة مرات تااستطعت استيعاب الفكرة
    من وؤاء ارجع وظيفية بدك قيمة في المثال الاول

    function add(x){
    return function(y){
    return x + y ;
    };
    };
    var add5 = add(5);
    alert(add5(3)); //8

    لو تلاحظ انه انشاء متغير واحطاه القيمة وهيا دالة وبما انه الدالة اعطاها قيمة تعود بدالة فاصبح بامكانه تشغيل هذه الدالة مرة اخرى فالظاهر يخدع ولكن الفكرة قوية
    var e=e();
    e(20);
    شكرا جزيلا للجميع وبخاصة كاتب المقالة ودمتم سالمين

  4. almhajer Says:

    الفكرة بسيطة اذا امعنت النظر هيا انشاء دالة تعيد قيمة لدالة مثال باسلوب المتغيرات
    var e=function(x){
    return function(t){
    alert(x+t);
    }
    }

    var t=e(2);
    t(10);

    بما اننا انشائنا متغير واعطيناه قيمة وبما ان القيمة تساوي دالة فيمكن استدعاء الدالة
    وهذا المثال يندرج تحت مفهوم صفوف التأشير الذاتي
    اي
    x=*x
    اشارة الضرب هيا مؤشر الى نفس الاجراء شكرا لصاحب المقالة ولاخ عمر وبراك الله فيكم وان اشء الله الى الامام

  5. almhajer Says:

    شكرا جزيلا

  6. محمد النادى Says:

    أنت متأكد انك دكتور صيدلى ….!! أنت مهندس برمجيات ومحترف كمان
    أنا قرأت ليك أكثر من موضوع انت رائع يامصطفى ربنا معاك

  7. محمد النادى Says:

    أنت معلم ياتيفااااااااااااااااااااا

أضف تعليقاً

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s


%d مدونون معجبون بهذه: