سؤال

سألت سؤال حول التمشيط و الإغلاق السابق ذكرها.ما هو الإغلاق ؟ كيف تتصل التمشيط?

هل كانت مفيدة؟

المحلول

نطاق متغير

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

function() {
  var a = 1;
  console.log(a); // works
}    
console.log(a); // fails

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

var a = 1;
function() {
  console.log(a); // works
}    
console.log(a); // works

عندما كتلة أو وظيفة عمله مع المتغيرات المحلية لم تعد هناك حاجة وعادة ما تخرج من الذاكرة.

هكذا عادة نتوقع من الأشياء.

الإغلاق هو استمرار المحلية نطاق متغير

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

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

هذا يعطينا وظيفة الحمل.يمكننا أن نتوقع أي المتغيرات التي كانت في نطاق عندما وظيفة لأول مرة أن يكون لا يزال في نطاق عندما كنا في وقت لاحق استدعاء الدالة, حتى لو كنا استدعاء الدالة في سياق مختلف تماما.

على سبيل المثال

هنا مثال بسيط حقا في جافا سكريبت أن يوضح هذه النقطة:

outer = function() {
  var a = 1;
  var inner = function() {
    console.log(a);
  }
  return inner; // this returns a function
}

var fnc = outer(); // execute outer to get inner 
fnc();

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

عادة عندما وظيفة المخارج جميع المتغيرات المحلية في مهب.ومع ذلك ، إذا عدنا الداخلية وظيفة تعيين إلى متغير fnc بحيث استمرت بعد outer وقد خرجت ، كل من المتغيرات التي كانت في نطاق عندما inner وعرف أيضا تستمر.المتغير a تم إغلاق أكثر-هو داخل الإغلاق.

لاحظ أن المتغير a هو تماما خاصة أن fnc.هذا هو وسيلة لخلق الخاصة المتغيرات الوظيفية لغة البرمجة مثل جافا سكريبت.

كما كنت قد تكون قادرة على تخمين, عندما اتصل fnc() فإنه يطبع قيمة a, الذي هو "1".

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

في جافا سكريبت ، متغير a استمرت لأن نطاق متغير يتم إنشاؤه عند الدالة أعلن لأول مرة ويستمر لمدة طالما وظيفة لا تزال موجودة.

a ينتمي إلى نطاق outer.نطاق inner وقد الوالدين المؤشر إلى نطاق outer. fnc هو المتغير الذي يشير إلى inner. a استمرت طالما fnc استمرت. a ضمن الإغلاق.

نصائح أخرى

سأعطيك مثال (في جافا سكريبت):

function makeCounter () {
  var count = 0;
  return function () {
    count += 1;
    return count;
  }
}

var x = makeCounter();

x(); returns 1

x(); returns 2

...etc...

ما هذه الوظيفة ، makeCounter هل هو إرجاع الدالة التي قمنا دعا x, التي سوف تحسب بنسبة واحد في كل مرة دعا لها.بما أننا لا تقدم أي المعلمات x يجب بطريقة أو بأخرى تذكر العد.فهو يعرف أين يمكن العثور عليه على أساس ما يسمى المعجمية تحديد النطاق - يجب أن ننظر إلى بقعة حيث أنها محددة لإيجاد قيمة.هذا "hidden" value هو ما يسمى الإغلاق.

هنا هو بلدي التمشيط المثال مرة أخرى:

function add (a) {
  return function (b) {
    return a + b;
  }
}

var add3 = add(3);

add3(4); returns 7

ما يمكنك رؤيته هو أنه عند استدعاء إضافة مع معلمة (3) ، أن القيمة الواردة في إغلاق عاد وظيفة أننا تحدد أن يكون add3.بهذه الطريقة, عندما ندعو add3 يعرف أين يمكن العثور على قيمة لأداء ذلك.

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

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

على سبيل المثال, عندما يكون لديك وظيفة جافا سكريبت:

function closed(x) {
  return x + 3;
}

وهو أغلقت التعبير لأن كل الرموز التي تحدث في ذلك المعرفة في ذلك (ومعانيها واضحة), حتى تتمكن من تقييم ذلك.وبعبارة أخرى ، هو مكتفية ذاتيا.

ولكن إذا كان لديك وظيفة مثل هذا:

function open(x) {
  return x*y + 3;
}

وهو فتح التعبير لأن هناك رموز في ذلك الأمر الذي لم يكن يعرف في ذلك.وهي y.عند النظر في هذه الوظيفة, نحن لا يمكن أن أقول ما y ما يعني أننا لا نعرف قيمته, لذلك لا يمكننا تقييم هذا التعبير.أولا-هاء.ونحن لا يمكن استدعاء هذه الدالة حتى نقول ما y يفترض أن يعني في ذلك.هذا y يسمى مجانا متغير.

هذا y يطرح التعريف ، ولكن هذا التعريف ليس جزءا من وظيفة – هو محدد في مكان آخر ، في "المحيطة السياق" (المعروف أيضا باسم البيئة).على الأقل هذا ما نأمل :P

على سبيل المثال, ويمكن تعريفه على الصعيد العالمي:

var y = 7;

function open(x) {
  return x*y + 3;
}

أو أنها يمكن أن تكون محددة في وظيفة التي يلتف عليه:

var global = 2;

function wrapper(y) {
   var w = "unused";

   return function(x) {
     return x*y + 3;
   }

}

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

في المثال أعلاه, وظيفة الداخلية (التي لم تعطي اسما لأنه لم يكن في حاجة إليها) هو فتح التعبير لأن المتغير y في ذلك هو مجانا – تعريفه هو خارج وظيفة في وظيفة التي يلتف عليه.على البيئة على أن وظيفة مجهول هو مجموعة من المتغيرات:

{
  global: 2,
  w: "unused",
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

الآن ، إغلاق هو أن جزءا من هذه البيئة التي يغلق الداخلية وظيفة خلال توفير التعاريف لجميع المتغيرات الحرة.في حالة واحدة فقط مجانا متغير في الدالة الداخلية كان y, لذا إغلاق تلك هي وظيفة هذه المجموعة الفرعية من البيئة:

{
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

وغيرها من اثنين من الرموز المحددة في البيئة لا جزء من إغلاق تلك المهمة لأنها لا تتطلب منهم إلى تشغيل.فهي ليست في حاجة إلى قريب ذلك.

أكثر على نظرية وراء ذلك هنا:https://stackoverflow.com/a/36878651/434562

الجدير ملاحظة أنه في المثال أعلاه ، المجمع الدالة بإرجاع الداخلية بمثابة قيمة.لحظة استدعاء هذه الدالة يمكن أن يكون جهاز التحكم عن بعد في الوقت من لحظة وظيفة تم تعريف (أو خلق).ولا سيما التفاف وظيفة لم يعد يعمل و المعايير التي تم على مكدس الاستدعاءات لم تعد هناك :P وهذا يجعل مشكلة ، لأن وظيفة الداخلية يحتاج y أن تكون هناك عندما ويسمى!وبعبارة أخرى ، فإنه يتطلب المتغيرات من الإغلاق بطريقة أو بأخرى تعمر وظيفة المجمع ويكون هناك عند الحاجة.وبالتالي فإن وظيفة الداخلية قد جعل لقطة هذه المتغيرات التي تجعل إغلاق وتخزينها في مكان آمن من أجل استخدامها في وقت لاحق.(في مكان ما خارج الاستدعاءات.)

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

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

def outer (a):
    b = "variable in outer()"
    def inner (c):
        print a, b, c
    return inner

# Now the return value from outer() can be saved for later
func = outer ("test")
func (1) # prints "test variable in outer() 1

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

لبدء يجب أن مفهوم الاسم.عند إدخال الأوامر إلى نظام مترجم ، يجب تقييم مختلف الرموز في التعبير والحصول على قيمتها.على سبيل المثال:

(define x 3)

(define y 4)

(+ x y) returns 7

تعريف التعبير تخزين القيمة 3 في بقعة x و قيمة 4 في بقعة y.ثم عندما نسميه (+ x y), المترجم بالبحث عن القيم في مساحة الاسم وغير قادرة على إجراء العملية والعودة 7.

ومع ذلك ، في مخطط هناك التعبيرات التي تسمح لك مؤقتا تجاوز قيمة الرمز.هنا مثال:

(define x 3)

(define y 4)

(let ((x 5))
   (+ x y)) returns 9

x returns 3

ما الكلمة اسمحوا لا يقدم مساحة جديدة مع x القيمة 5.ستلاحظ أنه لا يزال قادرا على رؤية أن y هو 4 ، مما يجعل المبلغ إلى 9.يمكنك أن ترى أيضا أنه بمجرد التعبير قد انتهت x هو يعود إلى كونها 3.في هذا المعنى, x مؤقتا من قبل ملثمين القيمة المضافة المحلية.

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

كيف ننفذ هذا ؟ طريقة بسيطة مع قائمة مرتبطة - رئيس يحتوي على القيمة الجديدة والذيل يحتوي على القديم مساحة الاسم.عندما كنت في حاجة للبحث عن الرمز, تبدأ في الرأس والعمل طريقك إلى أسفل الذيل.

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

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns ?

نحدد x 3 plus x-أن تكون المعلمة, y, بالإضافة إلى قيمة x.وأخيرا ندعو plus-x في بيئة حيث x قد تم من قبل ملثمين جديد x, هذا واحد بقيمة 5.إذا كنا مجرد مخزن العملية (+ x y) لوظيفة plus-x, وبما أننا في سياق x 5 والنتيجة عاد سيكون 9.هذا هو ما يسمى النطاق الديناميكي.

ومع ذلك, مخطط, Common Lisp و العديد من اللغات الأخرى ما يسمى المعجمية تحديد النطاق - بالإضافة إلى تخزين العملية (+ x y) كما مخزن مساحة الاسم في هذه النقطة بالذات.بهذه الطريقة, عندما كنا نبحث عن القيم يمكننا أن نرى أن x, في هذا السياق, هو حقا 3.هذا هو الإغلاق.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns 7

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

هنا هو مثال حقيقي على سبب الإغلاق ركلة الحمار...هذا هو مستقيم من شفرة جافا سكريبت.اسمحوا لي أن أبين.

Function.prototype.delay = function(ms /*[, arg...]*/) {
  var fn = this,
      args = Array.prototype.slice.call(arguments, 1);

  return window.setTimeout(function() {
      return fn.apply(fn, args);
  }, ms);
};

وهنا كيف يمكنك أن استخدامه:

var startPlayback = function(track) {
  Player.play(track);  
};
startPlayback(someTrack);

الآن تخيل أنك تريد تشغيل لبدء تأخر, مثل على سبيل المثال 5 ثوان في وقت لاحق بعد هذا مقتطف الشفرة يعمل.حسنا هذا سهل مع delay وهو الإغلاق:

startPlayback.delay(5000, someTrack);
// Keep going, do other things

عند استدعاء delay مع 5000ms, أول مقتطف يعمل ، ويخزن مرت في الحجج في ذلك الإغلاق.ثم 5 ثوان في وقت لاحق, عندما setTimeout رد يحدث الإغلاق لا يزال يحافظ على هذه المتغيرات ، لذلك يمكن استدعاء الدالة الأصلية مع المعلمات الأصلية.
هذا هو نوع من التمشيط ، أو وظيفة الديكور.

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

tl;dr

إغلاق وظيفة ونطاقه تعيين (أو) متغير.وهكذا فإن اسم الإغلاق:نطاق الوظيفة المغلقة و استخدامها تماما مثل أي كيان آخر.

في عمق ويكيبيديا أسلوب الشرح

وفقا لويكيبيديا, إغلاق هو:

تقنيات اسم راقب مفرداتيا ملزمة في اللغات مع وظائف من الدرجة الأولى.

ماذا يعني ذلك ؟ دعونا ننظر إلى بعض التعاريف.

سوف اشرح الإغلاق وغيرها من التعاريف المتعلقة باستخدام هذا المثال:

function startAt(x) {
    return function (y) {
        return x + y;
    }
}

var closure1 = startAt(1);
var closure2 = startAt(5);

console.log(closure1(3)); // 4 (x == 1, y == 3)
console.log(closure2(3)); // 8 (x == 5, y == 3)

وظائف من الدرجة الأولى

أساسا هذا يعني يمكننا استخدام وظائف مثل أي كيان آخر.يمكننا تعديل عليها ، تمريرة لهم الحجج ، العودة لهم من وظائف أو التنازل لهم عن المتغيرات.من الناحية الفنية, فهي مواطنين من الدرجة الأولى, ، ومن هنا جاء اسم:وظائف من الدرجة الأولى.

في المثال أعلاه ، startAt بإرجاع (مجهول) وظيفة التي تعمل على تعيين closure1 و closure2.لذا كما ترون جافا سكريبت يعامل يعمل تماما مثل أي كيانات أخرى (مواطنين من الدرجة الأولى).

اسم الملزمة

اسم الملزمة عن معرفة ما هي البيانات متغير (معرف) المراجع.نطاق هو المهم حقا هنا ، هذا هو الشيء الذي سوف يحدد كيف ملزم يتم حلها.

في المثال أعلاه:

  • في داخلي مجهول وظيفة هذا النطاق ، y لا بد أن 3.
  • في startAt's النطاق ، x لا بد أن 1 أو 5 (اعتمادا على الإغلاق).

داخل وظيفة مجهول هذا النطاق ، x لا بد أن أي قيمة ، لذلك يحتاج إلى حل في العلوي (startAt's) نطاق.

المعجمية النطاق

كما ويكيبيديا يقول, نطاق:

هي المنطقة من برنامج كمبيوتر حيث ملزم صالحة: حيث يمكن أن يكون اسم يستخدم للإشارة إلى الكيان.

هناك نوعان من التقنيات:

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

لمزيد من التفسير ، تحقق من هذا السؤال و نلقي نظرة على ويكيبيديا.

في المثال أعلاه, يمكننا أن نرى أن جافا سكريبت بشكل معجمي راقب, لأنه عندما x هو حل ملزم يتم البحث في الجزء العلوي (startAt's) النطاق ، استنادا إلى التعليمات البرمجية المصدر (مجهول الوظيفة التي تبدو على x هو تعريف الداخل startAt) وليس بناء على الاستدعاءات ، الطريق (نطاق أين) تم استدعاء الدالة.

التفاف (closuring) حتى

في هذا المثال ، عندما ندعو startAt, ، فإنه سيعود (الدرجة الأولى) وظيفة التي من شأنها أن تسند إلى closure1 و closure2 وبالتالي إغلاق إنشاء لأن تمرير المتغيرات 1 و 5 سوف يتم حفظها داخل startAt's النطاق الذي سيتم تضمينه مع إرجاع وظيفة مجهول.عندما ندعو هذا المجهول من خلال وظيفة closure1 و closure2 مع نفس الحجة (3), قيمة y سيتم العثور على الفور (كما أن المعلمة التي تعمل) ، ولكن x ليست ملزمة في نطاق وظيفة مجهول ، وبالتالي فإن القرار لا يزال في (بشكل معجمي) العلوي وظيفة نطاق (التي تم حفظها في إغلاق) حيث x تم العثور على الالتزام إما 1 أو 5.الآن نحن نعرف كل شيء عن الجمع بحيث يمكن أن تكون النتيجة عاد ، ثم طباعتها.

الآن يجب أن نفهم الإغلاق و كيف يتصرفون ، الذي هو جزء أساسي من جافا سكريبت.

التمشيط

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

الوظائف التي لا تحتوي على المتغيرات الحرة تسمى نقية وظائف.

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

var pure = function pure(x){
  return x 
  // only own environment is used
}

var foo = "bar"

var closure = function closure(){
  return foo 
  // foo is a free variable from the outer environment
}

src: https://leanpub.com/javascriptallongesix/read#leanpub-auto-if-functions-without-free-variables-are-pure-are-closures-impure

في الوضع الطبيعي ، المتغيرات لا بد من تحديد نطاق القاعدة:المتغيرات المحلية العمل فقط من خلال وظيفة محددة.الإغلاق هو وسيلة من كسر هذه القاعدة مؤقتا للراحة.

def n_times(a_thing)
  return lambda{|n| a_thing * n}
end

في التعليمات البرمجية أعلاه ، lambda(|n| a_thing * n} هو الإغلاق بسبب a_thing يشار لامدا (وظيفة مجهول الخالق).

الآن, إذا كنت وضعت الناتجة مجهول وظيفة في وظيفة متغير.

foo = n_times(4)

فو كسر عادي نطاق القاعدة والبدء في استخدام 4 داخليا.

foo.call(3)

عودة 12.

باختصار وظيفة المؤشر هو مجرد مؤشر إلى موقع في البرنامج رمز قاعدة (مثل برنامج مكافحة).في حين الإغلاق = وظيفة مؤشر + الإطار المكدس.

.

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

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

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

******************
Example of Closure
******************

var globalValue = 5;

function functOuter() 
{
    var outerFunctionValue = 10;

    //Inner function has access to the outer function value
    //and the global variables
    function functInner() 
    {
        var innerFunctionValue = 5;
        alert(globalValue+outerFunctionValue + innerFunctionValue);
    }
    functInner();
}
functOuter();

سوف يكون الإخراج 20 مجموع وظيفة الداخلية الخاصة المتغير الخارجي وظيفة متغير قيمة المتغير العالمي.

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

local old_dofile = dofile

function dofile( filename )
  if filename == nil then
    error( 'Can not use default of stdin.' )
  end

  old_dofile( filename )
end

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

من Lua.org:

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

إذا كنت من جافا العالم ، يمكنك مقارنة إغلاق مع وظيفة عضو من فئة.انظر هذا المثال

var f=function(){
  var a=7;
  var g=function(){
    return a;
  }
  return g;
}

وظيفة g هو الإغلاق: g يغلق a في.لذلك g يمكن مقارنة مع عضو وظيفة ، a يمكن مقارنة مع فئة الحقل, وظيفة f مع فئة.

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

Listing 2-18:
    function outerFunction(arg) {
     var variableInOuterFunction = arg;

     function bar() {
             console.log(variableInOuterFunction); // Access a variable from the outer scope
     }
     // Call the local function to demonstrate that it has access to arg
     bar(); 
    }
    outerFunction('hello closure!'); // logs hello closure!

المصدر: http://index-of.es/Varios/Basarat%20Ali%20Syed%20(مصادقة)-بداية%20Node.js-Apress%20(2014).pdf

يرجى إلقاء نظرة أدناه رمز لفهم إغلاق في أكثر عمقا:

        for(var i=0; i< 5; i++){            
            setTimeout(function(){
                console.log(i);
            }, 1000);                        
        }

هنا ماذا سيكون الناتج ؟ 0,1,2,3,4 لا أن يكون 5,5,5,5,5 بسبب الإغلاق

فكيف ستحلها ؟ الجواب هو التالي:

       for(var i=0; i< 5; i++){
           (function(j){     //using IIFE           
                setTimeout(function(){
                               console.log(j);
                           },1000);
            })(i);          
        }

اسمحوا لي شرح بسيط عندما وظيفة خلقت من لا شيء يحدث حتى ما يسمى حلقة في 1 رمز اتصلت 5 مرات ولكن لا يسمى فورا حتى عندما دعوت.ه بعد 1 ثانية و أيضا هذا غير متزامن حتى قبل هذا للحلقة النهائية وتخزين القيمة 5 في فار انا وأخيرا تنفيذ setTimeout الوظيفة الخامسة من الوقت و الطباعة 5,5,5,5,5

هنا كيفية حل باستخدام حياتي أنا.هـ الفور استدعاء وظيفة التعبير

       (function(j){  //i is passed here           
            setTimeout(function(){
                           console.log(j);
                       },1000);
        })(i);  //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4

لمزيد من فضلك فهم سياق التنفيذ لفهم الإغلاق.

  • هناك أكثر من حل واحد لحل هذه باستخدام السماح (ES6 ميزة) ولكن تحت غطاء محرك السيارة فوق وظيفة عمل

     for(let i=0; i< 5; i++){           
         setTimeout(function(){
                        console.log(i);
                    },1000);                        
     }
    
    Output: 0,1,2,3,4
    

=> مزيد من التوضيح:

في الذاكرة ، عندما للحلقة تنفيذ الصورة مثل أدناه:

حلقة 1)

     setTimeout(function(){
                    console.log(i);
                },1000);  

حلقة 2)

     setTimeout(function(){
                    console.log(i);
                },1000); 

حلقة 3)

     setTimeout(function(){
                    console.log(i);
                },1000); 

الحلقة 4)

     setTimeout(function(){
                    console.log(i);
                },1000); 

الحلقة 5)

     setTimeout(function(){
                    console.log(i);
                },1000);  

أنا هنا لا يتم تنفيذ ثم بعد حلقة كاملة, فار أنا تخزين القيمة 5 في الذاكرة لكنه نطاق هو دائما مرئية في الأطفال وظيفة حتى عندما وظيفة تنفيذ الداخل setTimeout خمس الوقت فإنه يطبع 5,5,5,5,5

لذا لحل هذه استخدام الحياة كما شرح أعلاه.

التمشيط :فإنه يسمح لك جزئيا تقييم وظيفة فقط يمر في مجموعة فرعية من الحجج.النظر في هذا:

function multiply (x, y) {
  return x * y;
}

const double = multiply.bind(null, 2);

const eight = double(4);

eight == 8;

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

function apple(x){
   function google(y,z) {
    console.log(x*y);
   }
   google(7,2);
}

apple(3);

// the answer here will be 21

الإغلاق من السهل جدا.يمكن أن نعتبر ذلك على النحو التالي :الإغلاق = وظيفة + لها المعجمية البيئة

نعتبر الدالة التالية:

function init() {
    var name = “Mozilla”;
}

ماذا سيكون الإغلاق في الحالة المذكورة أعلاه ?الدالة init() والمتغيرات في بيئة المعجمية أي اسم.إغلاق = init() + اسم

النظر في وظيفة أخرى :

function init() {
    var name = “Mozilla”;
    function displayName(){
        alert(name);
}
displayName();
}

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

إغلاق 1 : الحرف الأول وظيفة + ( اسم متغير + displayName (وظيفة)) -- > المعجمية نطاق

الإغلاق 2 : displayName وظيفة + ( اسم متغير ) --> المعجمية نطاق

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