Comments 61
Когда в функции объявляются переменные а потом гора вложенных функций используется. По сути как инстанс класса со своими полями, только всё приватно и вложено тут.
Пример. Другие примеры не отображаются на гихабе ввиду огромности размера файла.
https://github.com/Microsoft/TypeScript/blob/master/src/compiler/tsc.ts#L99
И работая с таким кодом повседневно, я не скажу что это лучшее решение. Хотя в некоторых местах катит. Но расширяемость и переиспользуемость сильно страдают. Иногда вынужден копипастить куски из компилера вместо того чтобы позвать.
Недавно читал интервью с создателем ява скрипта на хабре, говорит у него самого код без this выходит лучше. Ему толще посоветуете разобраться?
Крокфорд как-то ответил на ваш вопрос: в JS есть неоднозначные вещи, использование которых требует дисциплины и сакрального знания. this — одна из таких вещей (требует постоянно держать в уме контекст использования). То что требует повышенной дисциплины подвержено поломкам в результате человеческого фактора. Такие дела.
Кстати, очень легко проследить связь между "я пишу элегантный код, используя весь потенциал языка" и "я никому не доверю рефакторинг своего кода".
Теперь подумайте вот о чем:
1. На каждый экземпляр объекта созданного таким образом будут создаваться новые функции-методы. Это засоряет память, это убивает оптимизацию
Функции в js компилируются в момент первого вызова и оптимизируются при нескольких последующих вызовах. В случае Вашего подхода это будет делаться для каждого инстанса, что дорого, очень
Если же использовать правильный подход с прототипами функции будут созданы и скомпилированы только 1 раз, все инстансы будут использовать одну и ту же функцию. Мы экономим память. Инстанс создается быстрее. Инстанс работает быстрее, когда его методы уже скомпилированы при работе с предыдущим инстансом.
2. Как быть с наследованием? Допустим я хочу на базе Вашего двухсвязного списка сделать список с произвольным доступом на чтение и возможностью итерации. Если бы были прототипы — я бы относледовался от Вашего прототипа и добавил бы необходимые мне методы, но Ваш код я не смогу переиспользовать, это плохо
Замыкания не создают новых функций, они лишь хранят ссылки на контекст и на единожды созданную функцию. Тем не менее создание и хранение замыканий не бесплатно, да.
Замыкания, вопреки всеобщему заблуждению, — не функции. Это — структуры, хранящие две ссылки: на контекст и на собственно функцию (исполняемый код). Функция создаётся единожды при парсинге исходников.
Там никакого специального объекта нет.
Боюсь ошибиться, но кажется именно из спеки я о нём и узнал.
Не бойтесь: http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.3 :-)
Как вы думаете, что означает слово "let" в данном контексте?
То, что мы привыкли называть "замыканием" в спеке называется "объект функции", а собственно код функции находится в скрытом свойстве [[Code]] этого объекта и он общий для всех замыканий из одного места в исходниках: http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
А потом вот это
makeAdder(1) === makeAdder(1)
странно что по вашему мнению одна и та же функция возвращаемая при выполнении не равна сама себе
Никаких методов. Никаких конструкторов.
И стиль из ООП превращается в процедурное программирование
Например — стрелочные функции и привязка this. Как результат, при разработке можно практически полностью обойтись без this.
Вообще-то если не обращаться к this, то стрелочная функция ровно ничем не отличается от обычной:)
Дальше можно не читать, в общем.
Э… Я вижу просто явную передачу this в качестве аргумента функции (вместо обычной неявной), и всё. Что изменилось, кроме увеличения размера кода?
Уже можно через class properties:
class Foo {
bar = 'bar';
bound = () => console.log(this.bar);
}
Очень часто используется в React.
Да, только не привязанная к инстансу. А чтобы привязать для передачи метода, например, в виде колбэка, все-равно придется байндить руками на месте вызова (что порождает новую функцию на каждый вызов), либо в конструкторе. А класс-проперти — просто шорткат для конструктора.
Пример того как писать неподдерживаемый/корявый код.
из функции можно возвратить объект. Этот объект будет иметь доступ к локальному окружению
Это неверно. Объект ни к чему доступа иметь не может в принципе. Доступ к скоупу будут иметь только функции, в нём созданные. Всё. Они могут быть методами объекта, который вы вернёте, но сам объект тут ни при чём. Если вернуть объект вида { foo: 1 }, скоуп почистится сборщиком мусора. Если присвоить в качестве метода объекта функцию, объявленную снаружи, доступа к скоупу у неё тоже не будет.
Тут не имеет смысла ничего замыкать, модуль в котором вы пишите этот код делает это за вас:
module.exports = LinkedListDeque = (function() {
let Node = {
next: null,
prev: null,
data: null
};
let Deque = {
head: null,
tail: null,
length: 0
};
// тут нужно вернуть общедоступное API
})();
Этот код, во всех случаях, будет работать так-же:
let Node = {
next: null,
prev: null,
data: null
};
let Deque = {
head: null,
tail: null,
length: 0
};
module.exports = {
// тут нужно вернуть общедоступное API
};
Писать в таком стиле есть смысл, только, если помимо этого кода, в файле модуля есть еще какой-то функционал, от которого следует изолироваться, что уже было бы неправильно с точки зрения cohesion элементов внутри модуля.
Статья приводит хороший пример из функционального программирования, в частности, о преимуществе pure functions. К основному примеру, замыкания описанные выше, не имеют никакого отношения. Но этот пример, мог бы отлично продемонстрировать то, как можно применить каррирование, которое является отличным примером паттерна функционального программирования, который может помочь избавиться от this.
Такой подход позволяет работать и с this (он есть в замыкании, просто в своем коде вы его не применяете).
Такой подход хорош для эмуляции защищенных свойств и методов. Но отсутсвие вынести общее поведение в прототип приводит к тому, что каждый инстанс расходует больше памяти, нежели работа с цепочкой прототипов.
Еще в примере кода возвращается инстанс, лучше возвращать конструктор. Чтобы можно было создать свой инстанс, если потребуется более 1 инстанса модуля и провайдить настройки в конструктор, если модуль настраиваемый.
Посмотрите например на такой код:
https://github.com/Microsoft/TypeScript/blob/ceae613e4c0ba36829a2381687883ecdc6b169c3/src/services/services.ts#L1056
Такой код не расширяем и не переиспользуем от слова совсем. Есть примеры лучше, но там гитхаб не хочеть отображать большой файл.
JavaScript без this