function كيف تعمل إغلاق JavaScript؟





15 Answers

عندما ترى الكلمة الرئيسية للدالة ضمن وظيفة أخرى ، فإن الوظيفة الداخلية يمكنها الوصول إلى المتغيرات في الوظيفة الخارجية.

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

سيُسجل هذا دائمًا 16 ، لأن bar يمكنه الوصول إلى x الذي تم تعريفه كوسيطة foo ، ويمكنه أيضًا الوصول إلى tmp من foo .

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

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

ستقوم الدالة أعلاه بتسجيل 16 ، لأن bar لا يزال يشير إلى x و tmp ، على الرغم من أنه لم يعد مباشرة داخل النطاق.

ومع ذلك ، بما أن tmp لا يزال معلقًا داخل إغلاق bar ، فإنه يتم أيضًا زيادته. سيتم زيادتها في كل مرة تقوم فيها بالاتصال bar .

أبسط مثال على الإغلاق هو:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

عندما يتم استدعاء دالة JavaScript ، يتم إنشاء سياق تنفيذ جديد. مع وسيطات الدالة والكائن الرئيسي ، يتلقى سياق التنفيذ أيضًا جميع المتغيرات المعلنة خارجها (في المثال أعلاه ، كلاهما "أ" و "ب").

من الممكن إنشاء أكثر من وظيفة إغلاق واحدة ، إما عن طريق إعادة قائمة منها أو عن طريق تعيينها إلى المتغيرات العامة. كل هذا سيشير إلى نفس x ونفس الـ tmp ، لا يصنعون نسخهم الخاصة.

هنا الرقم x هو رقم حرفي. كما هو الحال مع القيم الحرفية الأخرى في JavaScript ، عندما يتم استدعاء foo ، يتم نسخ الرقم x إلى foo كوسيطة x .

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

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

كما هو متوقع ، سيتم كل استدعاء bar(10) زيادة x.memb . ما قد لا يكون متوقعًا ، هو أن x يشير ببساطة إلى نفس الكائن مثل متغير age ! بعد بضعة مكالمات bar ، age.memb سيكون 2! هذا المرجع هو أساس تسرب الذاكرة مع كائنات HTML.

javascript function variables scope closures

كيف تشرح إغلاق JavaScript لشخص ما لديه معرفة بالمفاهيم التي يتكون منها (على سبيل المثال ، الوظائف والمتغيرات وما شابه) ، ولكن لا يفهم الإغلاق بأنفسهم؟

لقد رأيت مثال المخطط المعطى على ويكيبيديا ، ولكن للأسف لم يساعد.




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

في مجال تنمية الطفولة: من 5 إلى 7 سنوات تقول:

سيتمكن طفلك من اتباع اتجاهين من خطوتين. على سبيل المثال ، إذا قلت لطفلك ، "اذهب إلى المطبخ وأحضري كيسًا للنفايات" سيكون بمقدوره تذكر ذلك الاتجاه.

يمكننا استخدام هذا المثال لشرح عمليات الإغلاق ، على النحو التالي:

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

يمكننا ترميز هذا في JavaScript مثل:

function makeKitchen() {
  var trashBags = ['A', 'B', 'C']; // only 3 at first

  return {
    getTrashBag: function() {
      return trashBags.pop();
    }
  };
}

var kitchen = makeKitchen();

console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A

مزيد من النقاط التي تشرح سبب الإغراءات المثيرة للاهتمام:

  • في كل مرة يتم استدعاء makeKitchen() ، يتم إنشاء إغلاق جديد باستخدام trashBags منفصلة خاصة به.
  • متغير trashBags محلي إلى داخل كل مطبخ ولا يمكن الوصول إليه بالخارج ، لكن الوظيفة الداخلية على الخاصية getTrashBag لها حق الوصول إليها.
  • تخلق كل مكالمة وظيفية إغلاقًا ، ولكن لن تكون هناك حاجة للحفاظ على الإغلاق ما لم يتم استدعاء وظيفة داخلية ، والتي يمكن الوصول إليها من داخل الإغلاق ، من خارج الإغلاق. إرجاع الكائن باستخدام الدالة getTrashBag هنا.



عمليات الإغلاق يصعب تفسيرها لأنها تستخدم في صنع بعض الأعمال السلوكية التي يتوقع الجميع أن يعملوا بها على أي حال. أجد أن أفضل طريقة لشرحهم (وطريقة تعلمهم ما يفعلونه) هي تخيل الوضع بدونهم:

    var bind = function(x) {
        return function(y) { return x + y; };
    }
    
    var plus5 = bind(5);
    console.log(plus5(3));

ما الذي يحدث هنا إذا لم تكن JavaScript تعرف الإغلاق؟ ما عليك سوى استبدال المكالمة الموجودة في السطر الأخير من خلال نص أسلوبها (وهو ما تقوم به الوظيفة بشكل أساسي) وتحصل على ما يلي:

console.log(x + 3);

الآن ، أين هو تعريف x ؟ لم نحدده في النطاق الحالي. الحل الوحيد هو السماح لـ plus5 بحمل نطاقه (أو بالأحرى نطاقه الأم). بهذه الطريقة ، يتم تعريف x بشكل جيد وهي مرتبطة بالقيمة 5.




حسنا ، مروحة الإغلاق عمرها 6 سنوات. هل تريد أن تسمع أبسط مثال على الإغلاق؟

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

إليك كيف يمكنني تحويل قصة طائرتي إلى الشفرة.

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");




لقد كتبت تعليقًا مدونًا منذ فترة لشرح عمليات الإغلاق. إليك ما قلته عن الإغلاق من حيث لماذا تريد واحدًا.

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

وبهذا المعنى ، فإنهم يجعلون دالة تعمل قليلاً مثل كائن ذي سمات خاصة.

المشاركة الكاملة:

فما هي هذه الأشياء الختامية؟




كيف سأشرح ذلك لعمر ست سنوات:

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




أنا أميل إلى التعلم بشكل أفضل من خلال مقارنات جيدة / سيئة. أحب أن أرى رمز العمل متبوعًا برمز لا يعمل والذي من المحتمل أن يواجهه شخص ما. لقد قمت بتجميع jsFiddle الذي يقوم بإجراء مقارنة ويحاول اختزال الاختلافات إلى أبسط التفسيرات التي يمكن أن أتوصل إليها .

عمليات الإغلاق تمت بشكل صحيح:

console.log('CLOSURES DONE RIGHT');

var arr = [];

function createClosure(n) {
    return function () {
        return 'n = ' + n;
    }
}

for (var index = 0; index < 10; index++) {
    arr[index] = createClosure(index);
}

for (var index in arr) {
    console.log(arr[index]());
}
  • في التعليمة البرمجية المذكورة أعلاه createClosure(n)يتم استدعاء في كل تكرار للحلقة. لاحظ أني سمّيت المتغير nلإبراز أنه متغير جديد تم إنشاؤه في نطاق وظيفي جديد وليس المتغير نفسه indexالذي يرتبط بالنطاق الخارجي.

  • هذا يخلق نطاق جديد nوملزم لهذا النطاق ؛ هذا يعني أن لدينا 10 نطاقات منفصلة ، واحدة لكل تكرار.

  • createClosure(n) بإرجاع دالة تقوم بإرجاع n داخل هذا النطاق.

  • داخل كل نطاق nيرتبط بأي قيمة لديه عندما createClosure(n)تم استدعاؤه ، لذا فإن الدالة المتداخلة التي يتم إرجاعها ستعود دائمًا بقيمة nما createClosure(n)تم احتوائه عندما تم استدعاؤه.

عمليات الإغلاق تمت بشكل خاطئ:

console.log('CLOSURES DONE WRONG');

function createClosureArray() {
    var badArr = [];

    for (var index = 0; index < 10; index++) {
        badArr[index] = function () {
            return 'n = ' + index;
        };
    }
    return badArr;
}

var badArr = createClosureArray();

for (var index in badArr) {
    console.log(badArr[index]());
}
  • في التعليمة البرمجية المذكورة أعلاه ، تم نقل الحلقة داخل createClosureArray()الدالة والدالة الآن فقط بإرجاع مجموعة مكتملة ، والتي تبدو للوهلة الأولى أكثر بديهية.

  • ما قد لا يكون واضحًا هو أنه createClosureArray()ما لم يتم استدعاؤه إلا بعد إنشاء نطاق واحد فقط لهذه الوظيفة بدلاً من واحد لكل تكرار للحلقة.

  • ضمن هذه الوظيفة indexيتم تعريف متغير مسمى . تعمل الحلقة وتضيف وظائف إلى الصفيف الذي يرجع index. ملاحظة indexيتم تعريفها داخل createClosureArrayالوظيفة التي يتم استدعاؤها مرة واحدة فقط.

  • نظرًا لوجود نطاق واحد فقط داخل createClosureArray()الدالة ، indexيتم ربطه فقط بقيمة داخل هذا النطاق. وبعبارة أخرى ، في كل مرة تقوم فيها الحلقة بتغيير قيمة index، فإنها تغيرها لكل ما يشير إليها ضمن هذا النطاق.

  • ترجع جميع الدالات المضافة إلى الصفيف indexمتغير SAME من النطاق الأصلي حيث تم تعريفه بدلاً من 10 منها مختلفة من 10 نطاقات مختلفة مثل المثال الأول. النتيجة النهائية هي أن كل الدالات العشرة تقوم بإرجاع نفس المتغير من نفس النطاق.

  • بعد الانتهاء من الحلقة والانتهاء indexمن تعديلها ، كانت القيمة النهائية 10 ، وبالتالي فإن كل دالة تُضاف إلى الصفيف تُرجع قيمة indexالمتغير الوحيد الذي تم تعيينه الآن على 10.

نتيجة

CLOSURES DET RIGHT
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9

CLOSURES Done WRONG
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10




قمت بتجميع برنامج تعليمي JavaScript تفاعلي لشرح كيفية عمل الإغلاقات. ما هو الإغلاق؟

إليك أحد الأمثلة:

var create = function (x) {
    var f = function () {
        return x; // We can refer to x here!
    };
    return f;
};
// 'create' takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here



لا أفهم لماذا تكون الإجابات معقدة للغاية هنا.

هنا إغلاق:

var a = 42;

function b() { return a; }

نعم فعلا. ربما تستخدم ذلك عدة مرات في اليوم.


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

الآن ما يسمح لك أن تفعل يمكن أن يكون أكثر إثارة، انظر إجابات أخرى.




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




أنت تنام و تدع دان أنت تخبر دان بإحضار وحدة تحكم XBox واحدة.

دان يدعو بول. يطلب دان من بول إحضار جهاز تحكم واحد. كم عدد المتحكمين الذين تم إحضارهم إلى الحفلة؟

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");



وقد أوضح مؤلف Closures عمليات الإغلاق بشكل جيد ، موضحًا سبب حاجتنا إليها وكذلك شرح LexicalEnvironment وهو أمر ضروري لفهم الإغلاق.
هذا هو الملخص:

ماذا لو تم الوصول إلى متغير ، لكنه ليس محليًا؟ مثلما هو الحال هنا:

في هذه الحالة ، يجد المترجم المتغير في LexicalEnvironmentالكائن الخارجي .

تتكون العملية من خطوتين:

  1. أولاً ، عند إنشاء دالة f ، لا يتم إنشاؤها في مساحة خالية. هناك كائن LexicalEnvironment الحالي. في الحالة أعلاه ، نافذة (غير معرّفة في وقت إنشاء الوظيفة).

عندما يتم إنشاء دالة ، تحصل على خاصية مخفية ، تسمى [[النطاق]] ، والتي تشير إلى LexicalEnvironment الحالية.

إذا تم قراءة متغير ، ولكن لا يمكن العثور عليه في أي مكان ، يتم إنشاء خطأ.

وظائف متداخلة

يمكن أن تتداخل الوظائف مع بعضها البعض ، لتشكل سلسلة من LexicalEnvironments والتي يمكن أن تسمى أيضًا سلسلة نطاق.

لذلك ، يمكن أن يكون للوظيفة g إمكانية الوصول إلى g و a و f.

إغلاق

قد تستمر الوظيفة المتداخلة في العمل بعد انتهاء الدالة الخارجية:

ترميز LexicalEnvironments:

كما نرى ، this.sayهي خاصية في كائن المستخدم ، لذلك تستمر في العيش بعد اكتمال المستخدم.

وإذا كنت تتذكر ، عندما this.sayيتم إنشاؤه ، فإنه (كل وظيفة) يحصل على مرجع داخلي this.say.[[Scope]]إلى LexicalEnvironment الحالي. لذلك ، يبقى LexicalEnvironment من تنفيذ المستخدم الحالي في الذاكرة. جميع متغيرات المستخدم هي أيضًا خصائصه ، لذلك يتم الاحتفاظ بها بعناية أيضًا ، ولا يتم حفظها كعادة.

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

كي تختصر:

  1. تحافظ الوظيفة الداخلية على مرجع إلى LexicalEnvironment الخارجي.
  2. يمكن للوظيفة الداخلية الوصول إلى المتغيرات منها في أي وقت حتى إذا تم الانتهاء من الوظيفة الخارجية.
  3. يحتفظ المتصفح بـ LexicalEnvironment وجميع خصائصه (المتغيرات) في الذاكرة حتى تكون هناك وظيفة داخلية تشير إليها.

وهذا ما يسمى إغلاق.




حسنًا ، عندما أتحدث مع طفل في السادسة من العمر ، ربما أستخدم الرابط التالي.

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

قارن مع موقف عندما كان الباب مقفل بواسطة المسودة ولا يوجد أحد داخل (تنفيذ الوظيفة العامة) ، ثم تحدث بعض الحرائق المحلية وحرق الغرفة (جامع القمامة: D) ، وبعد ذلك تم بناء غرفة جديدة والآن قد تترك ألعاب أخرى هناك (مثيل وظيفة جديدة) ، ولكن لم تحصل على نفس الألعاب التي تركت في مثيل الغرفة الأولى.

لطفل متقدم أود أن أضع شيئا مثل ما يلي. إنها ليست مثالية ، ولكنها تجعلك تشعر بما هي عليه:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

كما ترون ، لا يزال يمكن الوصول إلى الألعاب التي تُترك في الغرفة عبر الأخ بغض النظر عما إذا كانت الغرفة مغلقة أم لا. هنا jsbin للتلاعب به.




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

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

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

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

مثال:

function foo (initValue) {
   //This variable is not destroyed when the foo function exits.
   //It is 'captured' by the two nested functions returned below.
   var value = initValue;

   //Note that the two returned functions are created right now.
   //If the foo function is called again, it will return
   //new functions referencing a different 'value' variable.
   return {
       getValue: function () { return value; },
       setValue: function (newValue) { value = newValue; }
   }
}

function bar () {
    //foo sets its local variable 'value' to 5 and returns an object with
    //two functions still referencing that local variable
    var obj = foo(5);

    //Extracting functions just to show that no 'this' is involved here
    var getValue = obj.getValue;
    var setValue = obj.setValue;

    alert(getValue()); //Displays 5
    setValue(10);
    alert(getValue()); //Displays 10

    //At this point getValue and setValue functions are destroyed
    //(in reality they are destroyed at the next iteration of the garbage collector).
    //The local variable 'value' in the foo is no longer referenced by
    //anything and is destroyed too.
}

bar();



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

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




Related