Javascript blokerləri necə işləyir?

Bəstələndikləri konsepsiyaları (məsələn, funksiyalar, dəyişənlər və s.) Bilən kimsə üçün JavaScript-nin bağlanmasını necə izah edirsiniz, ancaq bağlanmaların özlərini anlamırsınız?

Vikipediyada verilən sxemdən bir nümunə gördüm, amma təəssüf ki, bu kömək etmədi.

7654
21 сент. 21 sentyabrda e-tenderə çıxdı. 2008-09-21 17:12 '08 at 5:12 pm 2008-09-21 17:12
@ 89 cavab
  • 1
  • 2
  • 3

Başlayanlar üçün javascriptin bağlanması

Morris tərəfindən təqdim olunub Tue, 2006-02-21 10:19. Cəmiyyət bundan bu günə qədər düzəldilmişdir.

Kapanma sehr deyil

Bu səhifə proqramçı onları başa düşə bilməsi üçün bağlanması izah edir - işləyən JavaScript kodu istifadə edir. Bu gurus və ya funksional proqramçılar üçün deyil.

Əsas konsepsiya düzəldildikdən sonra başa çatdırmaq çətin deyil. Ancaq nəzəri və ya akademik əsaslı şərhləri oxumaqla başa düşülə bilməzlər!

Bu məqalə bəzi əsas proqramlaşdırma təcrübəsi olan proqramçılar üçün nəzərdə tutulmuşdur və aşağıdakı JavaScript funksiyasını oxuyur:

birinci sinif xüsusiyyətləri dəstəkləmək üçün bir yoldur;  bir dəyişənə aiddir (əvvəlcədən elan edildiyi zaman), bir dəyişənə təyin edilmiş, bir funksiya arqumenti kimi qəbul edilmiş və ya bir funksiyanın nəticəsi olaraq qaytarılmış ola bilər. 

Yekun nümunəsi

Aşağıdakı kod bir funksiya istinadını verir:

 function say667() { // Local variable that ends up within closure var num = 42; var say = function() { console.log(num); } num++; return say; } var sayNumber = say667(); sayNumber(); // logs 43 

Məsələn 4

Bütün üç qlobal funksiya eyni yaxınlaşıb bir ümumi istinad edir, çünki bunların hamısı setupSomeGlobals() üçün vahid bir çağırış zamanı elan edilir.

 function sayAlice() { var say = function() { console.log(alice); } // Local variable that ends up within closure var alice = 'Hello Alice'; return say; } sayAlice()();// logs "Hello Alice" 

Tricky: Qeyd etmək lazımdır say dəyişən də bağlanma içərisindədir və sayAlice()sayAlice() elan edilə biləcək hər hansı bir funksiyanı ya da daxili bir sayAlice() içində recursively əldə edilə biləcəyini sayAlice() bilərik.

Misal 6

Bu, bütün insanlar üçün real sehrdir, buna görə anlamaq lazımdır. Bir loop içərisində bir funksiya təyin edərkən çox diqqətli olun: bağlanmadan gələn yerli dəyişənlər əvvəlcə düşündüyünüz kimi hərəkət edə bilməz.

Bu nümunəni anlamaq üçün javascript "dəyişən qaldırma" funksiyasını anlamaq lazımdır.

 function newClosure(someNum, someRef) { // Local variables that end up within closure var num = someNum; var anArray = [1,2,3]; var ref = someRef; return function(x) { num += x; anArray.push(num); console.log('num: ' + num + '; anArray: ' + anArray.toString() + '; ref.someVar: ' + ref.someVar + ';'); } } obj = {someVar: 4}; fn1 = newClosure(4, obj); fn2 = newClosure(5, obj); fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4; fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4; obj.someVar++; fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5; fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5; 

Xülasə

Hər şey tamamilə aydın deyilsə, nümunələrlə oynamaq yaxşıdır. Oxunan izah nümunələri anlamadan daha çətindir. Bağlama və yığma çərçivələrə dair izahatlar və s. Onlar texniki cəhətdən düzgün deyil - bunlar anlamaq üçün nəzərdə tutulmuş xam sadələşdiricilərdir. Əsas fikir həll olunduqdan sonra daha ətraflı məlumat əldə edə bilərsiniz.

Son nöqtələr:

  • function başqa bir funksiyadan istifadə edərkən, bağlanma istifadə olunur.
  • Bir funksiyanın içindəki eval() funksiyasını istifadə eval() yaxın istifadə olunur. eval mətn bir funksiyanı yerli dəyişənlərə istinad edə bilər və eval ilə eval('var foo = …') ilə yeni yerli dəyişənlər yarada bilərsiniz eval('var foo = …')
  • Bir funksiyanın içərisində new Function(…) ( funksiya konstruktoru ) istifadə etdikdə, yaxınlaşmır. (Yeni funksiya xarici funksiyanın yerli dəyişənlərinə istinad edə bilməz.)
  • JavaScript-də bağlanma funksiyası bir funksiyadan çıxdığınız kimi, bütün yerli dəyişənlərin bir nüsxəsini saxlamaq kimi.
  • Yəqin ki, bağlanma həmişə bir funksiya giriş kimi yaradılıb və bu dəyişikliyə yerli dəyişənlər əlavə olunacaqdır.
  • Hər bir funksiyanı bir bağlama ilə çağırırıq (funksiyanın içərisində bir funksiya bəyanatını ehtiva etdiyinə görə və ya bu daxili funksiyaya istinad ya geri qaytarılır və ya xarici istinad ona bir şəkildə saxlanılır) yeni bir sıra yerli dəyişənlər saxlanılır.
  • İki funksiya eyni mənbə koduna sahib kimi görünə bilər, ancaq gizli bağlanması səbəbiylə tamamilə fərqli bir davranış var. Hesab edirəm ki, JavaScript kodu həqiqətən bir funksiyanı bağlamaq olub-olmadığını öyrənə bilər.
  • Dinamik mənbə myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); hər hansı bir dəyişiklik etməyə myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); məsələn: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); ), myFunction bir bağlanma olsa (əlbəttə, iş vaxtında qaynaqların dəyişdirilməsini düşünmürsən, amma ...).
  • Funksiya deklarasiyalarını funksiya bəyannamələrinin içərisində mdash funksiyalarında əldə edə bilərsiniz və birdən çox səviyyəyə yaxınlaşa bilərsiniz.
  • Hesab edirəm ki, adətən bağlanma həm funksiya, həm də tutulan dəyişənlər üçün bir müddətdir. Xahiş edirik bu məqalədə bu tərifdən istifadə etməyəcəyəm!
  • Şübhə edirəm ki, JavaScript-də bağlanmalar funksional dildə yayılmış olanlardan fərqlənir.

əlaqələr

sayəsində

Əgər yaxınlaşdıqda (burada və ya bir yerdə başqa!) Öyrənsəniz, bu məqalənin daha aydın olmasını təklif edə biləcəyiniz hər hansı bir dəyişiklik barədə sizdən hər hansı bir rəy istəmirəm. Morrisjohns.com (morris_closure @) bir mesaj göndər. Xahiş edirəm ki, mən JavaScript-nin guru deyiləm - yaxın deyiləm.


Morris'in orijinal postu İnternet arxivində tapa bilərsiniz.

6329
21 сент. Cavab Joel Anair tərəfindən verilir 21 sep . 2008-09-21 17:18 '08 at 17:18 'da 2008-09-21 17:18

Funksiya açar sözünü başqa funksiyada görürsəniz, daxili funksiya xarici funksiyasındakı dəyişənlərə daxil olur.

 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); 

Yuxarıda göstərilən funksiya da 16 yazacaq, çünki bar artıq regionda artıq olmadığı halda xtmp ə müraciət edə bilər.

Bununla belə, tmp hələ də daxili bar bağlanması ətrafında asılıdır, çünki bu da artmaqdadır. Çubuğu çağırdığınız hər dəfə artacaq.

Bir bağlanmanın ən sadə nümunəsi aşağıdakılardır:

border=0

 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); 

Gözlənildiyi kimi, bar(10) hər bir çağırış bar(10) x.memb . x , age dəyişkənliyi ilə eyni obyektə sadəcə istinad etməyinizi xahiş edə bilməzsiniz! age.memb dair bir neçə age.memb 2- age.memb olacaq! Bu link HTML obyektləri ilə yaddaş sızması üçün əsas kimi xidmət edir.

3825
21 сент. Əliə 21 Sentyabrda cevap verildi . 2008-09-21 18:16 '08 at 6:16 pm 2008-09-21 18:16

Ön söz: sual bu sualın cavabında yazılmışdır:

Yaşlı Albert kimi, dedi: "Bunu altı yaşındakı bir uşağa izah edə bilmirsən, bunu sən başa düşmürsən". JS-nin 27 yaşlı bir dostun bağlanmasına izah etməyə çalışdım və tamamilə uğursuz oldum.

Hər kəs mənim 6 yaşım olduğunu düşünür və bu məsələ ilə qəribə maraqlana bilərmi?

Mən olduqca əminəm ki, ilk sualımı sanki mənimsəməyə çalışmış adamlardan biri oldum. O vaxtdan bəri, bu sual bir neçə dəfə dəyişildi, buna görə cavabım indi inanılmaz axmaq və qeyri-münasib görünür. Ümid edirəm ki, bu hekayənin ümumi ideyası maraqlıdır.


Mən mürəkkəb konsepsiyaları izah etməkdə analoji və metaforların böyük bir pərəstişkarıyam, buna görə əlimə tarixə nəzər salaq.

Bir zamanlar:

Bir şahzadə var idi ...

 function princess() { 

O macəra dolu gözəl bir dünyada yaşadı. O, şahzadə Çarlzla tanış oldu, dünyasını bir unicorn üzərində gəzdi, dragonsla mübarizə etdi, söhbət edən heyvanlarla və bir çox digər fantastik şeylərlə tanış oldu.

  var adventures = []; function princeCharming() {  } var unicorn = {  }, dragons = [  ], squirrel = "Hello!";  

Ancaq o, həmişə çətinlik və böyüklər onun darıxdırıcı dünyasına dönmək məcburiyyətində qaldı.

  return { 

Və tez-tez onlara bir şahzadə kimi son gözəl macəra haqqında danışdı.

  story: function() { return adventures[adventures.length - 1]; } }; } 

Ancaq gördüklərinin hamısı kiçik bir qız idi ...

 var littleGirl = princess(); 

... sehr və fantaziya haqqında hekayələr söyləmək.

 littleGirl.story(); 

Yetkinlər əsl prensler haqqında bilirdilərsə, heç vaxt unicorns və ya dragons heç inanmırdılar, çünki onlar heç vaxt onları görməmişdilər. Yetkinlər, yalnız kiçik bir qızın təsəvvürün içində olduqlarını söylədilər.

Amma biz əsl həqiqəti bilirik; bir şahzadə içərisində olan bir qız ...

... əslində içərisində kiçik bir qızla bir şahzadə.

2273
24 июня '11 в 21:49 2011-06-24 21:49 Cavab Yaqub Swartwood tərəfindən 24 iyun 'da 21:49' də verildi 2011-06-24 21:49

Bu sualı ciddi şəkildə nəzərə alaraq, 6 yaşlı tipik bir şəxsin bilikli olaraq bacarıqlı olduğunu bilmək lazımdır, buna baxmayaraq, JavaScript ilə maraqlananlar belə tipik deyildir.

Uşaqlıq inkişafı haqqında: 5 ildən 7 ilədək deyilir:

Çocuğunuz iki addımlıq istiqamətləri təqib edə biləcək. Məsələn, çocuğunuza deyirsinizsə: "Mətbəxə gedin və zibil qutusunu götürün", bu istiqamətdə xatırlayırlar.

Bu nümunəni aşağıdakı kimi izah etmək üçün istifadə edə bilərik:

A mətbəx yaxın bir yerdə olan trashBags adlı bir yerli dəyişən var. Mətbəx içərisində bir zibil paketini alan və geri qaytaran bir getTrashBag funksiyası var.

Bunu javascript ilə şifrələyə bilərsiniz:

696
02 сент. cavab dlaliberte 02 sep verilir . 2011-09-02 18:23 '11 'da 18:23' də 2011-09-02 18:23

Straw adam

Düymənin neçə dəfə basdırıldığını və hər üçüncü klikdə bir şey etməsini bilmək lazımdır ...

Çox açıq bir həll

 <button id="button">Click Me!</button> 

Bu artıq işləyəcək, ancaq xarici məqsədi hesabı izləmək üçün bir dəyişən əlavə edir. В некоторых ситуациях это было бы предпочтительнее, так как вашему внешнему приложению может потребоваться доступ к этой информации. Но в этом случае мы меняем только каждый третий клик, поэтому рекомендуется включать эту функциональность внутри обработчика событий .

Рассмотрим этот вариант

 <button id="button">Click Me!</button> 

Обратите внимание на несколько вещей здесь.

В приведенном выше примере я использую поведение закрытия JavaScript. Такое поведение позволяет любой функции иметь доступ к области, в которой она была создана, на неопределенный срок. Чтобы практически применить это, я немедленно вызываю функцию, которая возвращает другую функцию, и потому что возвращаемая функция имеет доступ к внутренней переменной счетчика (из-за описанного выше поведения закрытия), это приводит к закрытой области для использования в результате функция... Не так просто? Пусть разбавит его...

Простое однострочное закрытие

 // _______________________Immediately invoked______________________ // | | // | Scope retained for use ___Returned as the____ | // | only by returned function | value of func | | // | | | | | | // vvvvvv var func = (function() { var a = 'val'; return function() { alert(a); }; })(); 

Все переменные вне возвращаемой функции доступны для возвращаемой функции, но они не доступны непосредственно для возвращаемого объекта функции...

 func(); // Alerts "val" func.a; // Undefined 

Возьми? Поэтому в нашем основном примере переменная count содержится в закрытии и всегда доступна обработчику событий, поэтому сохраняет свое состояние от щелчка до щелчка.

Кроме того, это частное состояние переменной полностью доступно для обоих чтений и назначения его частным переменным.

Иди сюда; вы теперь полностью инкапсулируете это поведение.

Полная запись в блоге (включая соображения jQuery)

537
ответ дан jondavidjohn 26 февр. '13 в 22:40 2013-02-26 22:40

Замки трудно объяснить, потому что они используются, чтобы сделать какую-то поведенческую работу, которую все интуитивно ожидают в любом случае. Я нахожу лучший способ объяснить их (и то, как я узнал, что они делают) - представить ситуацию без них:

450
ответ дан Konrad Rudolph 21 сент. '08 в 17:24 2008-09-21 17:24

Это попытка прояснить несколько (возможных) недоразумений о замыканиях, которые появляются в некоторых других ответах.

  • Закрытие создается не только при возврате внутренней функции. Фактически, закрывающая функция не должна вообще возвращаться, чтобы ее замыкание было создано. Вместо этого вы можете назначить свою внутреннюю функцию переменной во внешней области или передать ее как аргумент другой функции, где ее можно было бы вызвать немедленно или в любое время позже. Поэтому закрытие закрывающей функции, вероятно, создается, как только вызывающая функция вызывается, поскольку любая внутренняя функция имеет доступ к этому закрытию всякий раз, когда вызывается внутренняя функция, до или после возвращения функции закрытия.
  • Закрытие не ссылается на копию старых значений переменных в своей области. Сами переменные являются частью замыкания, поэтому значение, наблюдаемое при доступе к одной из этих переменных, является самым последним значением в момент его доступа. Вот почему внутренние функции, созданные внутри циклов, могут быть сложными, поскольку каждый из них имеет доступ к тем же внешним переменным, а не к захвату копии переменных во время создания или вызова функции.
  • "Переменные" в закрытии включают любые именованные функции, объявленные внутри функции. Они также включают аргументы функции. Закрытие также имеет доступ к своим содержащим переменным замыкания, вплоть до глобальной области.
  • Закрытие использует память, но они не вызывают утечки памяти, поскольку JavaScript сам по себе очищает свои собственные циклические структуры, на которые не ссылаются. Утечки памяти Internet Explorer, связанные с закрытием, создаются, когда не удается отключить значения атрибутов DOM, которые ссылаются на блокировки, тем самым сохраняя ссылки на возможно круговые структуры.
344
ответ дан dlaliberte 08 апр. '10 в 16:54 2010-04-08 16:54

ОК, 6-летний вентилятор закрытия. Вы хотите услышать простейший пример закрытия?

Представьте себе следующую ситуацию: водитель сидит в машине. Этот автомобиль находится внутри самолета. Самолет находится в аэропорту. Способность водителя получать доступ к вещам вне его автомобиля, но внутри самолета, даже если этот самолет выходит из аэропорта, является закрытием. Это. Когда вам исполнится 27, взгляните на более подробное объяснение или на приведенный ниже пример.

Вот как я могу преобразовать историю своего самолета в код.

332
ответ дан Max Tkachenko 06 июня '13 в 13:22 2013-06-06 13:22

Закрытие очень похоже на объект. Он создается при каждом вызове функции.

Объем закрытия в JavaScript является лексическим, что означает, что все, что содержится в функции, к которой принадлежит замыкание, имеет доступ к любой переменной, которая в ней.

Переменная содержится в закрытии, если вы

  1. назначьте его var foo=1; və ya
  2. просто напишите var foo;

Если внутренняя функция (функция, содержащаяся внутри другой функции) обращается к такой переменной, не определяя ее в своей собственной области с помощью var, она изменяет содержимое переменной во внешнем закрытии.

Закрытие переживает время выполнения функции, которая породила его. Если другие функции выходят из замыкания/области действия, в которой они определены (например, как возвращаемые значения), они будут продолжать ссылаться на это закрытие.

пример

322
ответ дан Florian Bösch 21 сент. '08 в 17:20 2008-09-21 17:20

Я написал сообщение в блоге некоторое время назад, объясняя закрытие. Вот что я сказал о закрытии с точки зрения того, зачем вам это нужно.

Закрытие - это способ, позволяющий функции иметь постоянные частные переменные - то есть переменные, о которых знает только одна функция, где она может отслеживать информацию с предыдущих времен, когда она была запущена.

В этом смысле они позволяют функции действовать как объект с частными атрибутами.

Полное сообщение:

Итак, что это за закрытие?

216
ответ дан Nathan Long 07 февр. '11 в 23:57 2011-02-07 23:57

Закрытия просты:

Следующий простой пример охватывает все основные моменты закрытия JavaScript. *

Вот фабрика, которая производит калькуляторы, которые могут добавлять и умножать:

 function make_calculator() { var n = 0; // this calculator stores a single number n return { add: function(a) { n += a; return n; }, multiply: function(a) { n *= a; return n; } }; } first_calculator = make_calculator(); second_calculator = make_calculator(); first_calculator.add(3); // returns 3 second_calculator.add(400); // returns 400 first_calculator.multiply(11); // returns 33 second_calculator.multiply(10); // returns 4000 

Ключевой момент: Каждый вызов make_calculator создает новую локальную переменную n , которая продолжает быть полезными этим калькулятором add и multiply функции долго после make_calculator возвращается.

Если вы знакомы с фреймами стека, эти калькуляторы кажутся странными: как они могут продолжать доступ к n после make_calculator ? Ответ заключается в том, чтобы предположить, что JavaScript не использует "фреймы стека", но вместо этого использует "кучевые кадры", которые могут сохраняться после вызова функции, который заставлял их возвращаться.

Внутренние функции, такие как add и multiply , которые передают переменные, объявленные во внешней функции ** называются замыканиями.

Это почти все, что нужно для закрытия.



* Например, он охватывает все пункты статьи "Закрытия для чайников", приведенные в другом ответе , за исключением примера 6, который просто показывает, что переменные могут использоваться до их объявления, что является хорошим фактом, но совершенно не связанным с закрытием. Он также охватывает все точки принятого ответа , за исключением точек (1), которые копируют свои аргументы в локальные переменные (именованные аргументы функции) и (2) что копирование чисел создает новый номер, но копирование ссылки на объект дает вам другую ссылку на тот же объект. Они также хорошо знают, но снова полностью не связаны с закрытием. Он также очень похож на пример в этом ответе, но немного короче и менее абстрактен. Он не охватывает точку этого ответа или этого комментария , а это значит, что JavaScript затрудняет подключить текущее значение переменной цикла к вашей внутренней функции: шаг "запирания" может выполняться только с помощью вспомогательной функции, которая заключает вашей внутренней функции и вызывается на каждой итерации цикла. (Строго говоря, внутренняя функция обращается к копии вспомогательной функции переменной, а не к чему-либо подключенному.) Опять же, очень полезно при создании закрытий, но не в части того, что такое закрытие или как оно работает. Существует дополнительная путаница из-за того, что замыкания работают по-разному в функциональных языках, таких как ML, где переменные привязаны к значениям, а не к пространству хранения, обеспечивая постоянный поток людей, которые понимают закрытие способом (а именно "подключаемым" способом), который просто неверный для JavaScript, где переменные всегда привязаны к пространству хранения и никогда не относятся к значениям.

** Любая внешняя функция, если несколько вложенных или даже в глобальном контексте, как ясно указывает этот ответ .

199
ответ дан Matt 26 июня '13 в 1:22 2013-06-26 01:22

Как я объясню это шестилетнему ребенку:

Вы знаете, как взрослые могут владеть домом, и они называют его домом? Когда у мамы есть ребенок, ребенок действительно ничего не владеет, верно? Но его родители владеют домом, поэтому всякий раз, когда кто-то спрашивает ребенка "Где твой дом?", Он может ответить "на этот дом!" И указать на дом своих родителей. "Закрытие" - это способность ребенка всегда (даже если за границей) быть в состоянии сказать, что у него есть дом, хотя он действительно является родителем, который владеет домом.

196
ответ дан Magne 18 февр. '14 в 0:14 2014-02-18 00:14

Можете ли вы объяснить закрытие 5-летнего? *

Я все еще думаю, что объяснение Google работает очень хорошо и кратким:

  function outerFunction(someNum) { var someString = 'Hey!'; var content = document.getElementById('content'); function innerFunction() { content.innerHTML = someNum + ': ' + someString; content = null; // Internet Explorer memory leak for DOM reference } innerFunction(); } outerFunction(1);​ 

2019

187
ответ дан Chris S 20 апр. '10 в 11:16 2010-04-20 11:16

Я стараюсь лучше учиться на тестах GOOD/BAD. Мне нравится видеть рабочий код, за которым следует нерабочий код, с которым кто-то может столкнуться. Я собрал 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 различных областей, таких как первый пример. Конечным результатом является то, что все 10 функций возвращают одну и ту же переменную из той же области.

  • После того, как цикл завершен, и index был изменен, конечное значение равно 10, поэтому каждая функция, добавленная в массив, возвращает значение единственной index переменной, которая теперь установлена в 10.

результат

CLOSURES DONE 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

164
ответ дан Chev 19 июня '13 в 23:45 2013-06-19 23:45

Википедия о закрытии :

В информатике закрытие является функцией вместе со средой ссылок для нелокальных имен (свободных переменных) этой функции.

Технически, в JavaScript каждая функция является закрытием . Он всегда имеет доступ к переменным, определенным в окружении.

Поскольку конструкция, определяющая область видимости в JavaScript, является функцией , а не кодовым блоком, как на многих других языках, то , что мы обычно подразумеваем при закрытии в JavaScript, является функцией, работающей с нелокальными переменными, определенными в уже выполненной окружающей функции .

Закрытие часто используется для создания функций с некоторыми скрытыми частными данными (но это не всегда так).

 var db = (function() { // Create a hidden object, which will hold the data // it inaccessible from the outside. var data = {}; // Make a function, which will provide some access to the data. return function(key, val) { if (val === undefined) { return data[key] } // Get else { return data[key] = val } // Set } // We are calling the anonymous surrounding function, // returning the above inner function, which is a closure. })(); db('x') // -> undefined db('x', 1) // Set x to 1 db('x') // -> 1 // It impossible to access the data object itself. // We are able to get or set individual it. 

Эмс

В приведенном выше примере используется анонимная функция, которая была выполнена один раз. Но этого не должно быть. Его можно назвать (например, mkdb ) и выполнить позже, генерируя функцию базы данных каждый раз при ее вызове. Каждая сгенерированная функция будет иметь свой собственный скрытый объект базы данных. Другой пример использования замыканий - это когда мы не возвращаем функцию, а объект, содержащий несколько функций для разных целей, каждая из которых имеет доступ к тем же данным.

154
ответ дан mykhal 30 июля '11 в 17:27 2011-07-30 17:27

Я собрал интерактивный учебник по 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 
128
ответ дан Nathan Whitehead 26 июля '11 в 7:37 2011-07-26 07:37

Дети всегда будут помнить секреты, которые они поделили с родителями, даже после того, как их родители ушли. Это то, что закрывает для функций.

Секреты функций JavaScript - это частные переменные

 var parent = function() { var name = "Mary"; // secret } 

Каждый раз, когда вы вызываете его, создается локальная переменная "name" и имя "Mary". И каждый раз, когда функция выходит из переменной, теряется и имя забывается.

Как вы можете догадаться, поскольку переменные заново создаются каждый раз при вызове функции, и никто не узнает их, должно быть секретное место, где они хранятся. Его можно было бы назвать Тайной Палатой или стек или локальный охват, но это не имеет большого значения. Мы знаем, что они где-то скрыты в памяти.

Но в JavaScript есть особая вещь, что функции, созданные внутри других функций, также могут знать локальные переменные своих родителей и сохранять их до тех пор, пока они живут.

 var parent = function() { var name = "Mary"; var child = function(childName) { // I can also see that "name" is "Mary" } } 

Итак, пока мы находимся в родительском -function, он может создавать одну или несколько дочерних функций, которые разделяют секретные переменные из секретного места.

Но печально то, что если ребенок также является частной переменной своей родительской функции, он также погибнет, когда родитель закончится, и секреты умрут вместе с ними.

Чтобы жить, ребенок должен уйти до того, что он слишком поздно

 var parent = function() { var name = "Mary"; var child = function(childName) { return "My name is " + childName +", child of " + name; } return child; // child leaves the parent -> } var child = parent(); // < - and here it is outside 

И теперь, хотя Мэри "больше не бежит", память о ней не потеряна, и ее ребенок всегда будет помнить свое имя и другие секреты, которые они делили в свое время вместе.

Итак, если вы позвоните ребенку "Алиса", она ответит

 child("Alice") => "My name is Alice, child of Mary" 

Это все, что нужно сказать.

121
ответ дан Tero Tolonen 11 мая '15 в 19:35 2015-05-11 19:35

Я не понимаю, почему ответы здесь настолько сложны.

Вот закрытие:

 var a = 42; function b() { return a; } 

Да. Вы, вероятно, используете это много раз в день.


Нет никаких оснований полагать, что закрытие - это сложный дизайн для решения конкретных проблем. Нет, закрытие - это просто использование переменной, которая исходит из более высокой области видимости с точки зрения того, где была объявлена функция (не запускается) .

Теперь то, что он позволяет вам сделать, может быть более впечатляющим, см. Другие ответы.

100
ответ дан floribon 13 февр. '15 в 22:39 2015-02-13 22:39

Пример для первой точки dlaliberte:

Закрытие создается не только при возврате внутренней функции. Фактически, закрывающая функция вообще не нуждается в возврате. Вместо этого вы можете назначить свою внутреннюю функцию переменной во внешней области или передать ее в качестве аргумента другой функции, где ее можно будет использовать немедленно. Поэтому закрытие закрывающей функции, вероятно, уже существует в момент вызова функции-приложения, поскольку любая внутренняя функция имеет доступ к ней, как только она вызывается.

 var i; function foo(x) { var tmp = 3; i = function (y) { console.log(x + y + (++tmp)); } } foo(2); i(3); 
87
ответ дан someisaac 20 апр. '10 в 11:10 2010-04-20 11:10

Закрытие - это то, где внутренняя функция имеет доступ к переменным в своей внешней функции. Это, вероятно, самое простое однострочное объяснение, которое вы можете получить для закрытия.

81
ответ дан Rakesh Pai 22 сент. '08 в 0:39 2008-09-22 00:39

Я знаю, что уже есть много решений, но я думаю, что этот небольшой и простой скрипт может быть полезен для демонстрации концепции:

 // makeSequencer will return a "sequencer" function var makeSequencer = function() { var _count = 0; // not accessible outside this function var sequencer = function () { return _count++; } return sequencer; } var fnext = makeSequencer(); var v0 = fnext(); // v0 = 0; var v1 = fnext(); // v1 = 1; var vz = fnext._count // vz = undefined 
81
ответ дан Gerardo Lima 03 мая '12 в 21:16 2012-05-03 21:16

Вы спите, и вы приглашаете Дэн. Вы говорите Дэну, чтобы он привел один контроллер XBox.

Дэн приглашает Павла. Дэн просит Павла взять одного контроллера. Сколько контроллеров было доставлено на вечеринку?

77
ответ дан StewShack 20 июля '11 в 6:51 2011-07-20 06:51

Функции JavaScript могут получить доступ к следующим функциям:

  1. аргументы
  2. Локали (то есть их локальные переменные и локальные функции)
  3. Окружающая среда, которая включает:
    • глобальные, включая DOM
    • что-либо во внешних функциях

Если функция обращается к своей среде, то функция является закрытием.

Обратите внимание, что внешние функции не требуются, хотя они предлагают преимущества, которые я здесь не обсуждаю. Получая доступ к данным в своей среде, закрытие сохраняет эти данные. В подслучае внешних/внутренних функций внешняя функция может создавать локальные данные и, в конечном счете, выходить, и, тем не менее, если какая-либо внутренняя функция выживает после выхода внешней функции, тогда внутренняя функция сохраняет внешние данные внешней функции в живых.

Пример закрытия, использующего глобальную среду:

Представьте, что события кнопки "Переполнение стека" и "Голос-вниз" реализованы как закрытие, voteUp_click и voteDown_click, которые имеют доступ к внешним переменным isVotedUp и isVotedDown, которые определены глобально. (Для простоты я имею в виду кнопки StateOverflow Question Vote, а не массив кнопок Answer Vote).

Когда пользователь нажимает кнопку VoteUp, функция voteUp_click проверяет, является ли isVotedDown == true, чтобы определить, следует ли голосовать или просто отменить нисходящее голосование. Функция voteUp_click - это закрытие, потому что оно обращается к своей среде.

 var isVotedUp = false; var isVotedDown = false; function voteUp_click() { if (isVotedUp) return; else if (isVotedDown) SetDownVote(false); else SetUpVote(true); } function voteDown_click() { if (isVotedDown) return; else if (isVotedUp) SetUpVote(false); else SetDownVote(true); } function SetUpVote(status) { isVotedUp = status; // Do some CSS stuff to Vote-Up button } function SetDownVote(status) { isVotedDown = status; // Do some CSS stuff to Vote-Down button } 

Все четыре из этих функций являются закрытием, поскольку все они получают доступ к своей среде.

73
ответ дан John Pick 24 февр. '11 в 4:37 2011-02-24 04:37

Автор Closures очень хорошо объяснил закрытие, объясняя причину, по которой мы нуждаемся в них, а также объясняем LexicalEnvironment, которая необходима для понимания закрытий.
Вот резюме:

Что делать, если переменная доступна, но она не является локальной? Как здесь:

2019

ответ дан Arvand 15 авг. '15 в 16:38 2015-08-15 16:38

Будучи отцом 6-летнего ребенка, который в настоящее время обучает маленьких детей (и относительного новичка для кодирования без формального образования, так что исправления будут необходимы), я думаю, что урок будет лучше всего играть в практической игре. Если 6-летний человек готов понять, что такое закрытие, тогда они уже достаточно взрослые, чтобы пройти сами. Я бы предложил вставить код в jsfiddle.net, немного объяснив, и оставив их в покое, чтобы придумать уникальную песню. Пояснительный текст ниже, вероятно, более подходит для 10-летнего возраста.

 function sing(person) { var firstPart = "There was " + person + " who swallowed "; var fly = function() { var creature = "a fly"; var result = "Perhaps she'll die"; alert(firstPart + creature + "\n" + result); }; var spider = function() { var creature = "a spider"; var result = "that wiggled and jiggled and tickled inside her"; alert(firstPart + creature + "\n" + result); }; var bird = function() { var creature = "a bird"; var result = "How absurd!"; alert(firstPart + creature + "\n" + result); }; var cat = function() { var creature = "a cat"; var result = "Imagine That!"; alert(firstPart + creature + "\n" + result); }; fly(); spider(); bird(); cat(); } var person="an old lady"; sing(person); 

ИНСТРУКЦИИ

ДАННЫЕ: Данные представляют собой совокупность фактов. Это могут быть цифры, слова, измерения, наблюдения или даже просто описания вещей. Вы не можете прикоснуться к нему, почувствовать запах или попробовать его. Вы можете записать его, говорить и слышать. Вы можете использовать его для создания сенсорного запаха и вкуса с помощью компьютера. Это может быть полезно с помощью компьютера с использованием кода.

КОД: Все записи выше называются кодом. Он написан на JavaScript.

JAVASCRIPT: JavaScript - это язык. Как английский, французский или китайский языки. Существует множество языков, которые понимаются компьютерами и другими электронными процессорами. Для того чтобы JavaScript понимал компьютер, ему нужен интерпретатор. Представьте, что учитель, который говорит только по-русски, учит ваш класс в школе. Когда учитель говорит "все садятся", класс не поймет. Но, к счастью, у вас есть русский ученик в вашем классе, который говорит всем, что это означает, что "все садятся" - так вы все и делаете. Класс похож на компьютер, а русский ученик - переводчик. Для JavaScript наиболее распространенный интерпретатор называется браузером.

BROWSER: Когда вы подключаетесь к Интернету на компьютере, планшете или телефоне, чтобы посетить веб-сайт, вы используете браузер. Примеры, которые вы, возможно, знаете, - это Internet Explorer, Chrome, Firefox и Safari. Браузер может понять JavaScript и сообщить компьютеру, что ему нужно делать. Инструкции JavaScript называются функциями.

ФУНКЦИЯ: Функция в JavaScript похожа на фабрику. Это может быть небольшая фабрика с одной машиной внутри. Или он может содержать много других небольших фабрик, каждый из которых имеет множество машин, выполняющих разные рабочие места. На фабрике одежды реального времени у вас могут появиться полоски ткани и бобины нитки, а также футболки и джинсы. Наша фабрика JavaScript обрабатывает только данные, она не может шить, сверлить отверстие или расплавить металл. На нашем JavaScript заводские данные поступают и данные выводятся.

Все эти данные звучат немного скучно, но это действительно очень круто; у нас может быть функция, которая сообщает роботу, что делать на обед. Скажем, я приглашаю вас и вашего друга в мой дом. Вам больше нравятся куриные ножки, мне нравятся колбасы, ваш друг всегда хочет, чего вы хотите, а мой друг не ел мяса.

У меня нет времени ходить по магазинам, поэтому функция должна знать, что у нас есть в холодильнике, чтобы принимать решения. У каждого ингредиента есть другое время приготовления, и мы хотим, чтобы все было подано горячим роботом одновременно. Нам нужно предоставить функцию с данными о том, что нам нравится, функция может "разговаривать" с холодильником, а функция может управлять роботом.

Функция обычно имеет имя, круглые скобки и фигурные скобки. Как это:

 function cookMeal() {  } 

Обратите внимание, что и // останавливают чтение кода браузером.

NAME: вы можете вызвать функцию практически любого слова, которое вы хотите. Пример "cookMeal" типичен для объединения двух слов, а второй - заглавной буквы в начале, но это необязательно. Он не может иметь места в нем, и он не может быть числом сам по себе.

PARENTHESES: "Круглые скобки" или () - это поле для письма на заводской двери функции JavaScript или почтовый ящик на улице для отправки пакетов информации на завод. Иногда почтовый ящик может быть отмечен, например, cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime) , и в этом случае вы знаете, какие данные вы должны предоставить.

BRACES: "Подтяжки", которые выглядят так {} являются тонированными окнами нашего завода. Изнутри фабрики вы можете видеть, но снаружи вы не можете видеть.

ПРИМЕР ДОПОЛНИТЕЛЬНОГО КОДА ВЫШЕ

Наш код начинается со словарной функции, поэтому мы знаем, что это одно! Тогда имя функции sing - это мое собственное описание того, что представляет собой функция. Затем скобки(). Круглые скобки всегда существуют для функции. Иногда они пустые, и иногда у них есть что-то. У этого есть слово в: (person) . После этого есть такая скобка { . Это знаменует начало функции sing(). У этого есть партнер, который отмечает конец sing() как это }

 function sing(person) {  } 

Таким образом, эта функция может иметь какое-то отношение к пению и может потребоваться некоторые данные о человеке. У этого есть инструкции внутри, чтобы сделать что-то с этими данными.

Теперь, после функции sing(), ближе к концу кода находится строка

 var person="an old lady"; 

VARIABLE: буквы var обозначают "переменная". Переменная подобна конверту. Снаружи в этом конверте отмечается "человек". С внутренней стороны он содержит клочок бумаги с информацией, которую нам нужна наша функция, некоторые буквы и пространства, соединенные вместе, как часть строки (она называется струной), которые делают фразу, читающую "старушку". Наш конверт может содержать другие типы вещей, такие как числа (называемые целыми числами), инструкции (называемые функциями), списки (называемые массивами). Поскольку эта переменная написана вне всех фигурных скобок {} , и потому, что вы можете видеть сквозь тонированные окна, когда находитесь внутри фигурных скобок, эту переменную можно увидеть из любого места в коде. Мы называем это "глобальной переменной".

GLOBAL VARIABLE: человек - глобальная переменная, означающая, что если вы измените свою ценность от "старой леди" до "молодого человека", человек будет оставаться молодым человеком, пока вы не решите изменить его снова и что любая другая функция в код может видеть, что это молодой человек. Нажмите кнопку F12 или посмотрите настройки параметров, чтобы открыть консоль разработчика браузера и введите "человек", чтобы узнать, что это за значение. Тип person="a young man" чтобы изменить его, а затем снова наберите "человек", чтобы увидеть, что он изменился.

После этого у нас есть линия

 sing(person); 

Эта строка вызывает функцию, как если бы она вызывала собаку

"Come on sing, Come and get person!"

Когда браузер загрузил код JavaScript и достиг этой строки, он запустит эту функцию. Я положил строку в конец, чтобы убедиться, что браузер имеет всю информацию, необходимую для ее запуска.

Функции определяют действия - основная функция - пение. Он содержит переменную, называемую firstPart, которая относится к пению о человеке, который относится к каждому из стихов песни: "Был" + человек + ", который проглотил". Если вы введете firstPart в консоль, вы не получите ответ, потому что переменная заблокирована в функции - браузер не может видеть внутри тонированных окон фигурных скобок.

ЗАКРЫТИЯ: Закрытие - это меньшие функции, которые находятся внутри большой функции sing(). Маленькие фабрики на большой фабрике. У каждого из них есть свои собственные фигурные скобки, которые означают, что переменные внутри них не видны снаружи. Поэтому имена переменных (существа и результат) могут повторяться в закрытии, но с разными значениями. Если вы введете эти имена переменных в окне консоли, вы не получите его значение, потому что оно скрыто двумя слоями тонированных окон.

Все замыкающие знают, что переменная функции sing() называется firstPart, потому что они могут видеть из своих тонированных окон.

После замыканий приходят линии

 fly(); spider(); bird(); cat(); 

Функция sing() будет вызывать каждую из этих функций в том порядке, в котором они заданы. Затем будет работать функция sing().

58
ответ дан grateful 29 окт. '14 в 2:53 2014-10-29 02:53

Хорошо, разговаривая с 6-летним ребенком, я, возможно, буду использовать следующие ассоциации.

Представьте себе, что вы играете со своими маленькими братьями и сестрами во всем доме, и вы двигаетесь с вашими игрушками и приводите некоторых из них в свою комнату старшего брата. Через некоторое время ваш брат вернулся из школы и пошел в свою комнату, и он заперся внутри, так что теперь вы не могли получить доступ к игрушкам, оставленным там прямо. Но вы могли бы постучать в дверь и спросить своего брата за игрушками. Это называется закрытием игрушек; ваш брат сделал это для вас, и теперь он находится во внешнем пространстве.

Сравните с ситуацией, когда дверь была заблокирована сквозняком и никем внутри (выполнение общей функции), а затем произошел какой-то локальный пожар и сжег комнату (сборщик мусора: D), а затем была построена новая комната, и теперь вы можете уйти другие игрушки там (новый экземпляр функции), но никогда не получают те же игрушки, которые остались в первом экземпляре комнаты.

Для продвинутого ребенка я бы поставил что-то вроде следующего. Это не идеально, но это заставляет вас чувствовать, что это такое:

 function playingInBrothersRoom (withToys) { // We closure toys which we played in the brother 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 inner use. var brotherGivesToyBack = function (toy) { // New request. There is not yet closureToys on brother 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 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, чтобы поиграть с ним.

52
ответ дан dmi3y 04 марта '13 в 21:27 2013-03-04 21:27

Ответ для шестилетнего ребенка (предполагая, что он знает, что такое функция и какая переменная, и какие данные):

Функции могут возвращать данные. Еще одна функция - один из видов данных, которые вы можете вернуть из функции. Когда эта новая функция возвращается, все переменные и аргументы, используемые в созданной ей функции, не исчезают. Вместо этого эта родительская функция "закрывается". Другими словами, ничто не может заглянуть внутрь него и увидеть используемые переменные, кроме функции, которую она вернула. Эта новая функция обладает особой способностью оглядываться внутри функции, которая ее создала, и видеть внутри нее данные.

 function the_closure() { var x = 4; return function () { return x; // Here, we look back inside the_closure for the value of x } } var myFn = the_closure(); myFn(); //=> 4 

Другой действительно простой способ объяснить это с точки зрения объема:

Каждый раз, когда вы создаете меньшую область видимости в более широкой области, меньшая область всегда сможет увидеть, что находится в более широкой области.

48
ответ дан Stupid Stupid 16 мая '13 в 23:52 2013-05-16 23:52

Функция в JavaScript - это не просто ссылка на набор инструкций (как на языке C), но также включает скрытую структуру данных, которая состоит из ссылок на все нелокальные переменные, которые она использует (захваченные переменные). Такие функции из двух частей называются замыканиями. Каждая функция в JavaScript может считаться замыканием.

Закрытие - это функции с состоянием. Это несколько похоже на "это" в том смысле, что "это" также предоставляет состояние для функции, но функция, а "это" - отдельные объекты ("это" - просто причудливый параметр и единственный способ привязать его к функция - создать закрытие). Хотя "это" и функция всегда живут отдельно, функция не может быть отделена от ее закрытия, и язык не предоставляет никаких средств для доступа к захваченным переменным.

Поскольку все эти внешние переменные, на которые ссылается лексически вложенная функция, на самом деле являются локальными переменными в цепочке ее лексически охватывающих функций (глобальные переменные можно считать локальными переменными некоторой корневой функции), и каждое отдельное выполнение функции создает новые экземпляры его локальные переменные, следует, что при каждом выполнении функции, возвращающей (или иным образом передающей ее, например, регистрации ее в качестве обратного вызова), вложенная функция создает новое замыкание (с его собственным потенциально уникальным набором ссылочных нелокальных переменных, которые представляют его выполнение контекст).

Кроме того, следует понимать, что локальные переменные в JavaScript создаются не в стеке стека, а в куче и уничтожаются только тогда, когда никто не ссылается на них. Когда функция возвращается, ссылки на ее локальные переменные уменьшаются, но они все равно могут быть не равными нулю, если во время текущего выполнения они стали частью замыкания и по-прежнему ссылаются на его лексически вложенные функции (что может произойти, только если ссылки на эти вложенные функции были возвращены или иным образом перенесены на некоторый внешний код).

Məsələn:

 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(); 
47
ответ дан srgstm 25 окт. '12 в 21:12 2012-10-25 21:12

Возможно, немного выше всех, кроме самых ранних шестилетних, но несколько примеров, которые помогли мне сделать концепцию закрытия в JavaScript.

Закрытие - это функция, которая имеет доступ к другой области функций (ее переменные и функции). Самый простой способ создать замыкание - это функция внутри функции; причина в том, что в JavaScript функция всегда имеет доступ к ее содержащимся в ней функциям.

 function outerFunction() { var outerVar = "monkey"; function innerFunction() { return outerVar; } return innerFunction; } var referenceToInnerFunction = outerFunction(); alert(referenceToInnerFunction()); 

ALERT: обезьяна

referenceToInnerFunction устанавливается на externalFunction(), который просто возвращает ссылку на innerFunction. Когда вызывается referenceToInnerFunction, он возвращает outerVar. Опять же, как и выше, это демонстрирует, что innerFunction имеет доступ к externalVar, переменной внешней функции. Кроме того, интересно отметить, что он сохраняет этот доступ даже после завершения внешней функции.

И здесь все становится действительно интересным. Если бы мы избавились от externalFunction, скажем, установим его в null, вы можете подумать, что referenceToInnerFunction потеряет свой доступ к значению externalVar. Но это не так.

 function outerFunction() { var outerVar = "monkey"; function innerFunction() { alert(outerVar); } outerVar = "gorilla"; innerFunction(); } outerFunction(); 

ALERT: горилла

Во-вторых, когда создается замыкание, он сохраняет ссылку на все свои функции и функции включения функций; он не получает, чтобы выбрать и выбрать. И все же, закрытие должно использоваться экономно или, по крайней мере, тщательно, поскольку они могут быть интенсивными в памяти; многие переменные могут храниться в памяти многократно после завершения выполнения содержащейся функции.

46
ответ дан Michael Dziedzic 02 марта '15 в 21:08 2015-03-02 21:08

Я просто укажу их на страницу Mozilla Closures . Это лучшее, кратчайшее и простое объяснение основ закрытия и практического использования, которые я нашел. Настоятельно рекомендуется всем, кто изучает JavaScript.

И да, я бы даже рекомендовал его 6-летнему - если 6-летний учитель узнает о закрытии, тогда логично, что они готовы понять краткое и простое объяснение, приведенное в статье.

43
ответ дан mjmoody383 09 марта '13 в 6:24 2013-03-09 06:24
  • 1
  • 2
  • 3

Другие вопросы по меткам или Задайте вопрос