• На собеседовании сказали, что не все функции - замыкания. Так ли это?

    @Arlekcangp
    Разработчик, Лид, Архитектор ПО
    Похоже вас поймали на том что в js кто-то решил переопределить термин "замыкание"... Т к javascript далеко не первый язык, в котором есть нечто, претендующее называться термином "замыкание", то следует в первую очередь рассмотреть общее определение. Возьмём его из википедии:

    Замыкание (англ. closure) в программировании — функция первого класса, в теле которой присутствуют ссылки на переменные, объявленные вне тела этой функции в окружающем коде и не являющиеся её параметрами. Говоря другим языком, замыкание — функция, которая ссылается на свободные переменные в своей области видимости.
    Замыкание, так же как и экземпляр объекта, есть способ представления функциональности и данных, связанных и упакованных вместе.
    Замыкание — это особый вид функции. Она определена в теле другой функции и создаётся каждый раз во время её выполнения. Синтаксически это выглядит как функция, находящаяся целиком в теле другой функции. При этом вложенная внутренняя функция содержит ссылки на локальные переменные внешней функции. Каждый раз при выполнении внешней функции происходит создание нового экземпляра внутренней функции, с новыми ссылками на переменные внешней функции.
    В случае замыкания ссылки на переменные внешней функции действительны внутри вложенной функции до тех пор, пока работает вложенная функция, даже если внешняя функция закончила работу, и переменные вышли из области видимости.[1]
    Замыкание связывает код функции с её лексическим окружением (местом, в котором она определена в коде). Лексические переменные замыкания отличаются от глобальных переменных тем, что они не занимают глобальное пространство имён. От переменных в объектах они отличаются тем, что привязаны к функциям, а не объектам.


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

    In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function[a] together with an environment.[1] The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.[b] Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.


    О! А тут нет никаких "функций, вложенных в функцию" и нет никаких "создающихся каждый раз" Хм... Интересно. Ну за то есть абзац о том как появились замыкания:

    The concept of closures was developed in the 1960s for the mechanical evaluation of expressions in the λ-calculus and was first fully implemented in 1970 as a language feature in the PAL programming language to support lexically scoped first-class functions.[2]

    Peter J. Landin defined the term closure in 1964 as having an environment part and a control part as used by his SECD machine for evaluating expressions.[3] Joel Moses credits Landin with introducing the term closure to refer to a lambda expression whose open bindings (free variables) have been closed by (or bound in) the lexical environment, resulting in a closed expression, or closure.[4][5] This usage was subsequently adopted by Sussman and Steele when they defined Scheme in 1975,[6] a lexically scoped variant of Lisp, and became widespread.


    Ага. Оказывается первоначально они появились в такой не конвенциональной, с сегодняшней точки зрения VM, как SECD... И их создатель прямо говорит, что это код плюс данные. Далее термин применяют к лямбда-выражениям. Ничего не говорится, должны ли эти выражения возвращаться функцией, или достаточно того, что бы они захватывали переменные из своего лексического (или динамического, как в common lisp) окружения. Далее нам сообщают, что некие мистеры, Сасман и Стил, спустя каких то 11 лет добавили это в свой язык Scheme... Ну что же. Посмотрим замыкания в Scheme... А именно откроем книгу Сасмана и соавторов "Структура и интерпретация компьютерных программ" или "SICP" Первый раз (исключая содержание) слово "замыкание" встречается в главе 2 "Поcтроение абстракций c помощью данных"


    Важная идея в работе с составными данными — понятие замыкания (closure): клей для
    сочетания объектов данных должен позволять нам склеивать не только элементарные
    объекты данных, но и составные.


    Но, как выяснилось, это не те замыкания... Это замыкание в том смысле, что структуру одного типа (в данном случае пары) могут ссылаться на самих себя. И это то как термин "замыкание" понимают математики. Далее в SICP никаких других определений замыканий нет (несмотря на то, что само их использование конечно же есть) Ну ничего не остаётся как посмотреть что же сегодня называют замыканиями в языке Scheme... Гугл по этому запросу выдал первой ссылкой: https://www.cs.utexas.edu/ftp/garbage/cs345/schint....
    Цитирую:

    Procedures are Closures
    Scheme procedure's aren't really just pieces of code you can execute; they're closures.

    A closure is a procedure that records what environment it was created in. When you call it, that environment is restored before the actual code is executed. This ensures that when a procedure executes, it sees the exact same variable bindings that were visible when it was created--it doesn't just remember variable names in its code, it remembers what storage each name referred to when it was created.

    Since variable bindings are allocated on the heap, not on a stack, this allows procedures to remember binding environments even after the expressions that created those environments have been evaluated. For example, a closure created by a lambda inside a let will remember the let's variable bindings even after we've exited the let. As long as we have a pointer to the procedure (closure), the bindings it refers to are guaranteed to exist. (The garbage collector will not reclaim the procedure's storage, or the storage for the let bindings.)

    Here's an example that may clarify this, and show one way of taking advantage of it.

    Suppose we type the following expression at the Scheme prompt, to be interpreted in a top-level environment:

    Scheme> (let ((count 0))
               (lambda ()
                  (set! count (+ count 1))
                  count)))

    ##

    Evaluating this let expression first creates a binding environment with a binding for count. The initial value of this binding is 0. In this environment, the lambda expression creates a closure. When executed, this procedure will increment the count, and then return its value. (Note that the procedure is not executed yet, however--it's just created.) This procedure, returned by the lambda expression, is also returned as the value of the let expression, because a let returns the value of its last body expression. The read-eval-print loop therefore prints a representation of the (anonymous) procedure.


    Что имеем ? В Scheme - вообще любая функция - это замыкание! Т к она всегда захватывает контекст, даже если там пусто!. Что видим в коде ? Ну с точки зрения Scheme тут конечно вложенная функция, т к let - это на самом деле lambda, но так происходит потому, что в Scheme нет переменных в понимании js. В js же можно считать, что глобальный контекст - результат действия нечто, что эквивалентно let. Захватывает ли любая функция в js этот контекст ? Не знаю. Но точно знаю, что в вашем примере это определенно так - х часть контекста, который захватывается функцией. Кто хочет поспорить - идите спорьте с создателями Scheme (скажите, когда попкорн покупать, я посмотрю как вас пороть будут. Набежало тут вайтишников =)) Кто то может сказать "а вот у нас в js замыкания определяются не так" На что я отвечу: знаете, товарищи, а идите ка вы лесом! Если есть однажды созданный и определенный термин, нужны весьма веские причины что бы менять его определение. Желания левой ноги очередного вайтишника тут не достаточно.
    Ответ написан
    30 комментариев
  • Как Сверстать направляющие от блока к блоку(border змейкой)?

    wapster92
    @wapster92 Куратор тега CSS
    Ответ написан
    Комментировать
  • Разумно ли конвертировать изображения в base64 и сохранять в базу?

    DevMan
    @DevMan
    хранить изображения в бд, в любом виде, в большинстве случаев - идея бестолковая.
    Ответ написан
    Комментировать
  • Как написать быстрый парсер на PHP?

    kshnkvn
    @kshnkvn
    yay ✌️ t.me/kshnkvn
    Так а скорости то хватает? Если предположить, что средний вес загружаемой страницы ~450кб, то для загрузки 25 таких страниц как раз нужно ~90 мбит/сек: 450кб * 25 = 11250кб/сек = 11,25мб/сек = 90мбит/сек.
    Ответ написан
    4 комментария
  • Как вы решили проблему адаптивности таблиц?

    @JustFreelance
    front-end developer
    Есть решение с использованием data-атрибутов и перестроением в блочный вид на CSS.

    https://codepen.io/just_freelance/pen/RwPvWmj
    Ответ написан
    1 комментарий
  • Что сейчас востребовано на фрилансе?

    sergey-gornostaev
    @sergey-gornostaev
    Седой и строгий
    На фрилансе востребованы люди, способные самостоятельно проанализировать заказы и сделать выводы.
    Ответ написан
    Комментировать
  • Как правильно делать оптимизацию чтобы сайт моментально загружался?

    @grinat
    1. Заходим в index.html
    2. Все удаляем
    3. ???
    4. Сайт мгновенно загружается
    Ответ написан
    1 комментарий
  • Какие области в веб - разработке осваивать в перспективе?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Надеюсь, вопрос закроют как дубль. Потому что ну сколько можно уже. "Я ничего не знаю, ни к чему душа особо не лежит, но хочу быть молодым перспективным владельцем стартапов, газет, пароходов поэтому скажите мне какой язык программирования делает людей богатыми и успешными. но только чтобы особо напрягаться не нужно было!"
    Ответ написан
    4 комментария
  • Как адаптивно сверстать идеально круглые блоки с контентом на CSS?

    dimovich85
    @dimovich85 Куратор тега CSS
    https://u-academy.net/
    Есть способ как сделать стороны с любимым соотношением.
    Сначала создается div, или любой блочный элемент, ему задается необходимая ширина и border-radius 50%. В этот блок вкладывается другой блок с высотой 0 и padding-top такой, какой надо для пропорции, только задается он в процентах. В данном случае это padding-top: 100%, а для соотношения 16:9 padding-top: 56.9%, если память не изменяет. Также этому блоку задается position relative. В этот блок вкладываем еще один блок, который получает position absolute, width 100% height 100%. Уже в этот последний, третий, блок вкладываем контент.
    Ответ написан
    2 комментария
  • Как экспортировать большие данные в excel?

    Jump
    @Jump
    Системный администратор со стажем.
    В excel подается обычный текст, никакие формулы внутри не используются

    Так а зачем на пхп пытаться всунуть данные именно в XLSX ?
    Не проще ли просто выгрузить их из БД и сохранить в банальный CSV, с которым EXCEL прекрасно взаимодействует.
    Ответ написан
    3 комментария
  • Cookie или localStorage?

    @artinnok
    бекенд-программист
    Тут нет оптимального варианта - надо смотреть на бэкэнд и фронтенд совокупно.
    Далее, считаем что фронтенд SPA, бэкэнд чистое API.

    Если выбор за Cookies:
    1. На сервере необходимо реализовать защиту от CSRF
    2. На фронте также надо будет реализовать обвязку под передачу CSRF-токена
    3. Вся авторизация будет обрабатываться бэкэндом - т.е. он ставит куку через Set-Cookie с httpOnly и secure и сам же читает из куки для аутентификации / авторизации
    4. Фронтенд не имеет доступа к кукам - не думает об авторизации и об XSS
    5. Обычно, XSS используют чтобы украсть авторизационный токен через JS - если авторизационная кука httpOnly - нет доступа к кукам через JS, нет проблем

    Если выбор за localStorage:
    1. Не надо делать CSRF защиту на сервере - нет кук, нет проблем
    2. Экранировать потенциально опасные данные бэкэндом на входе - обеспечит дополнительную защиту от XSS при рендере данных
    3. Надо делать защиту от XSS на фронте, т.е. экранирование данных при рендере - чтобы потенциально вредоносный JS код превращался в строку, а не вставлялся в DOM
    4. На фронте надо сделать обвязку под сохранение / передачу / валидацию токена
    5. Всегда остается человеческий фактор - забыли сделать экранирование при рендере на фронте, JS код имеет доступ к токену и он утек


    Могу посоветовать использовать фреймворки, как на бэкэ, так и на фронте - они обычно имеют уже реализованную защиту от основных типов атак. Мы на проекте юзаем localStorage и React, ну и верим в лучшее :)
    Ответ написан
  • Адаптивный анимированный слайдер?

    KazeZlat
    @KazeZlat
    Погромист-затейник
    Прочитать описание к посту и найти Github разработчика.
    https://github.com/Cuberto/liquid-swipe
    Ответ написан
  • Как сверстать шапку такой формы?

    Ankhena
    @Ankhena Куратор тега CSS
    Нежно люблю верстку
    Без SVG, картинок и псевдоэлементов,
    CSS only

    Ответ написан
    24 комментария
  • .Gitignore - как исключить вложенную папку через одну?

    @lexnekr Автор вопроса
    Нашёл решение сам.

    1) исключаем папку
    admin/*

    2) игнорируем исключением дочки
    !admin/modules/

    3) исключаем содержимое дочки
    admin/modules/*

    4) игнорируем исключение дочки
    !admin/modules/name/

    ИТОГО:

    admin/*
    !admin/modules/
    admin/modules/*
    !admin/modules/name/
    Ответ написан
    2 комментария