Чому закриття важливе для JavaScript?


16

Лямбда-вираз C # також має закриття, але рідко обговорюється спільнотами або книгами C #. Я бачу набагато більше людей і книг JavaScript говорять про його закриття, ніж вони роблять у світі C #. Чому так?


3
Оскільки JavaScript трактується як функціональна мова першого класу, а C # є класичним мовою OOP. Різні парадигми, різні стилі програмування.
Райнос

1
Функція першого класу робить цю мову функціональною мовою. PHP (з 5.3), python або D має функцію першого класу. Ви б сказали, що вони функціональні мови? Звичайно, ні, і javascript також.
deadalnix

1
@deadalnix JavaScript - це багатопарадигмальна мова. В основному він підтримує процедурну, функціональну та прототипічну парадигму ОО. Це аж ніяк не чиста функціональна мова, але ви можете легко писати javascript у функціональній парадигмі без згинання мови. Я б сказав те саме C # і python.
Райнос

3
@deadalnix, мова, яка дозволяє визначити Y-комбінатор, є функціональною мовою. За визначенням.
SK-логіка

1
@deadalnix: Я вважаю, що це зводиться до питання, які підходи пропагує мова. Існує багато фреймворків та платформ JavaScript (зокрема node.js та DOM (подійна модель)), які значною мірою покладаються на функції першого порядку. У PHP є функції, які дозволяють використовувати той самий стиль програмування, але якщо ви подивитесь на стандартний API або багато фреймворків, то ви побачите, що це насправді не в основі мови.
back2dos

Відповіді:


5

Оскільки у JavaScript немає такої функції, як простори імен, і ви можете легко псувати з усіма глобальними об’єктами.

Тому важливо вміти ізолювати якийсь код у власному середовищі виконання. Закриття ідеально підходить для цього.

Таке використання закриття не має сенсу для такої мови, як C #, де у вас є простори імен, класи тощо, щоб ізолювати код і не ставити все в глобальну сферу.

Дуже поширена практика коду javascript - це писати так:

(function(){
    // Some code
})();

Як бачите, це анонімне оголошення функції з подальшим негайним його виконанням. Таким чином, до всього, що визначено в межах функції, неможливо отримати доступ ззовні, і ви не зіпсуєте глобальну область. Контекст виконання цієї функції залишатиметься активним до тих пір, поки якийсь код використовує його, як вкладені функції, визначені в цьому контексті, які ви можете передавати як зворотний виклик або будь-який інший.

Javascript - це зовсім інша мова, ніж C #. Він не орієнтований на об’єкти, він орієнтований на прототип. Це призводить до дуже різних практик наприкінці.

У всякому разі, закриття є гарними, тому використовуйте їх навіть у C #!

EDIT: Після деяких обговорень в чаті stackoverflow я думаю, що цю відповідь потрібно точно уточнити.

Функція у зразковому коді не є закриттям. Однак цей funntion може визначати локальну змінну та вкладені функції. Усі вкладені функції, які використовують ці локальні змінні, - це закриття.

Це корисно для обміну деякими даними через набір функцій, не псуючи глобальну сферу. Це найпоширеніше використання закриття в JavaScript.

Закриття набагато потужніше, ніж просто обмін деякими подібними даними, але давайте бути реалістичними, більшість програмістів нічого не знає про функціональне програмування. У C # ви б використовували клас або простір імен для подібного використання, але JS не забезпечує цю функціональність.

З закриттям можна зробити більше, ніж просто захистити глобальну область, але це те, що ви побачите у вихідному коді JS.


9
Це не закриття. Ви описуєте перевагу використання функцій для створення локальної області.
Райнос

2
закриття - це лише закриття, якщо воно закривається над вільними змінними. Також дякую, що сказали мені, що не знаю, як працює JavaScript :)
Raynos

2
а не вдаватися до підриву, називаючи мене початківцем, сміливо висувайте фактичні аргументи в кімнаті чату JavaScript SO . Ця дискусія насправді не належить тут, але я із задоволенням обговорю ваші помилки в чаті SO.
Райнос

1
Захищений. JavaScript орієнтований на велику кількість об'єктів. Це просто не на основі класу, але такий функціонал легко створити. Він має функції першого класу, використовує переваги для закриття, щоб зробити його природним придатним для сильно керованих подіями парадигм, а головним джерелом натхнення за словами його автора Брендана Ейха була схема. Я не дуже впевнений, що, на вашу думку, є функціональною мовою, але смішним є те, що, здається, ви вважаєте, що спадкування на основі класу є якимось важливим, а не більше цілком необхідним, коли ви можете передавати функції та застосовувати їх у нових контекстах.
Ерік Реппен

2
-1 також. Це не описує закриття, воно описує сферу застосування.
Ізката

12

Можливо, тому, що популярні реалізації об'єктної орієнтації JavaScript залежать від закриттів. Розглянемо простий приклад:

function counter() {
   var value = 0;
   this.getValue = function() { return value; }
   this.increase = function() { value++; }
}

var myCounter = new counter();
console.log(myCounter.getValue());
myCounter.increase();
console.log(myCounter.getValue());

Методи getValueі increaseфактично є закриттями, інкапсулюючи змінну value.


3
-1 "залежить від закриття" Це дуже суб'єктивно. Це не.
Райнос

Raynos: хочете показати нам, як створювати та використовувати приватних членів без закриття?
користувач281377

1
@ammoQ у JavaScript немає такого поняття, як приватне. Ви мали на увазі те, що "класична емуляція OO залежить від закриття". JavaScript OO є прототипним, що є іншою парадигмою. Хоча це гарна відповідь на питання: "Ми використовуємо закриття в JavaScript, тому що потрібно було наслідувати класичний OO"
Raynos

1
@keppla Я мав на увазі "OO залежить від закриття" є суб'єктивним. Вам не потрібні закриття для ОО.
Райнос

2
ти виставляєш мене як реп-шлюха, який я ...
user281377

4

Тому що багато бібліотек, які роблять JavaScript 'терплячим', використовують їх.

Погляньте на JQuery , Prototype або MooTools , лише щоб назвати три популярні. Кожна з цих бібліотек надає eachметод для своїх колекцій як кращий спосіб ітерації, який використовує функцію ітератора. Ця функція при доступі до значень у зовнішній області буде закриттям:

[1,2,3].each(function(item) {
   console.log(item);
});

І це на цьому не зупиняється: зворотні виклики в Ajax, обробка подій у Ext.js і т. Д. Всі беруть на себе функції, і якщо ви не хочете роздути свій код 100-ма функціями, які викликаються точно один раз, закриття - це шлях.


1
Чому це не закриття? console.logвизначається у зовнішній області, тому consoleє "вільною змінною". І чому, насправді, це цикл for-петлі, який не робить нічого іншого, погана практика?
keppla

@Raynos: моє визначення закриття - це "блок, який містить вільну змінну", він не втрачає цього статусу, але вільна змінна, можливо, знаходиться у верхній області. Але, щоб підтримати мою думку, розглянемо цей метод: pastie.org/2144689 . Чому це має бути погано?
кеппла

Я все ще думаю, що «закриття» глобальних даних вважається обманом. Я погоджуюсь, що доступ до даних по ланцюгу сфери застосування є прекрасним, просто мінімізувати доступ.
Райнос

Домовились про мінімізацію доступу
keppla

Слід зазначити, що в ітераторах масивів (forEach, map, зменшення тощо) немає нульової причини, щоб вони були закритими, у них весь стан перейшов безпосередньо в них. Я вважаю, що це анти-модель для закриття
Райнос

3

Я погоджуюся з іншими відповідями, що "хороше" кодування JavaScript значною мірою залежить від закриття. Однак, на додаток до цього, мабуть, лише питання про те, як довго ця функція існує в кожній мові. В основному JavaScript закрився з моменту його раннього впровадження. З іншого боку, у C # вони були лише з 3.0, який вийшов разом з Visual Studio 2008.

Дуже багато програмістів на C #, з якими я стикаюся, досі працюють над проектами 2.0. І навіть якщо вони працюють у версії 3.0 або 4.0, вони часто все ще використовують ідіоми 2.0. Я люблю закриття; сподіваємось, вони стануть більш активно використовуватися в C #, коли концепція поширюється серед розробників C #.


2

Основна причина полягає в тому, що C # набраний статично і функції мають лише доступ до єдиного заздалегідь визначеного середовища, що перешкоджає корисності закриття.

З іншого боку, закриття дозволяє функціям функціонувати як методи, коли вони отримують доступ як властивість об'єкта і будучи об'єктами першокласного класу, вони також можуть бути введені в різні середовища, що дозволяє підпрограмам працювати в різних контекстах.


1
Що стосується статичного введення тексту? Замикання є ортогональними.

-1

Однією з причин, що мені довелося дізнатися про них, було те, що коли ви перебираєте елементи DOM (або що-небудь справді), ви хочете мати можливість "закрити" або "інкапсулювати" змінну область. Як у прикладі, розміщеному тут: /programming/5606059/how-to-create-closure-in-loop-and-store-it-in-variable-for-later-execution

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.