Статьи

Закрытие и волшебство карри для чистого JavaScript

Иногда вы найдете кусок JavaScript , идеальный фрагмент JavaScript, он делает именно  то , что вам нужно! Отлично! Вы могли потратить часы, даже дни, заставить что-то работать, и кто-то уже сделал это, даже поделился кодом в интернете!

Ура!

Но … код выглядит примерно так:

// to populate later
var data = [], oldData = [], semiOldData = [];
var a_switch = "blah";
 
function do_something() {
   // use subset of globals
}
 
function something_else() {
   // use some other globals
}
 
// etc.
 
function update() {
  // use all of the above
}

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

Но это будет проблемой — код сильно зависит от состояния. Хорошо, может быть, объектно-ориентированный? Объектно-ориентированный вид — отстой в javascript, и вам придется все это перекодировать, понимать и т. Д.

Боль в заднице!

Закрытие магии

Есть лучший способ — положить его в закрытие.

var my_widget = (function (data_function) {
// to populate later
var data = [], oldData = [], semiOldData = [];
var an_index = 1;
 
function do_something() {
   // use subset of globals
}
 
function something_else() {
   // use some other globals
}
 
// etc.
 
function update(index) {
  an_index = index;
  data = data_function();
  // use all of the above
}
 
return update;
});

Теперь вы можете создать виджет с помощью простого вызова функции. Ура!

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

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

Закрытие на закрытие

Вот где это становится еще более волшебным. Укладка крышек для достижения истинного величия.

Код — лучший способ объяснить, что я имею в виду …

// these functions are used to slice up data
var slice_functions = {
        students: function (item) { return !!item.cs_student; },
        others: function (item) { return !item.cs_student; },
        everyone: function (item) { return true; }
    },
        slice_func = slice_functions.students,
 
// these functions provide cleaned up data
// all must use the same main slice_func
        data_functions = {
            year_vs_pay: function (year) {
                var data = DATA.filter(slice_func).filter(function (item) {
                    return item.years_study == year;
                }),
                // ...
                return fin_data;
            },
            study_vs_pay: function (study) {
                var data = DATA.filter(slice_func).filter(function (item) {
                    return item.study_time == study;
                }),
                // ...
                return fin_data;
            },
            // ...

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

Теперь перейдем к сложной части — мы можем внешне изменить slice_func,  и все data_functions (теперь безопасно скрытые внутри замыканий)  изменят  свое поведение, используя новую функцию slice_function, поскольку переменные внутри замыканий являются указателями, а не копиями.

Магия!

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

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

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