Defront — про фронтенд-разработку и не только
20K subscribers
21 photos
1.09K links
Ламповый канал про фронтенд и не только. Всё самое полезное для опытных web-разработчиков

Обсуждение постов @defrontchat

Также советую канал @webnya
Download Telegram
Продолжаем чтение статей Акселя Раушмайера (что поделать, они очень хороши). В этот раз попалась статья про оптимизацию хвостовых вызовов (tail call optimization - TCO) в ES2015.

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

Наличие оптимизации хвостовых вызовов помогает реализовывать рекурсивные алгоритмы более органично. Жаль только, что TCO, похоже, не скоро будет добавлен в v8 (Chromium) и SpiderMonkey (Firefox) из-за проблем с его реализацией. Поддержка TCO пока только есть в Safari.

#js #tco #fp #es2015

http://2ality.com/2015/06/tail-call-optimization.html
Майлз Боринз три дня назад открыл пулл-реквест в Node.js с обновлённой имплементацией поддержки ES2015 Modules.

Самое значимое изменение – возможность использовать новые модули в файлах с расширением *.js. Теперь в Node.js есть три возможности работать с новыми модулями:
1) используя расширение *.mjs;
2) используя расширение *.js и type: module в package.json;
3) используя расширение *.js и флаги командной строки --type=module / -m.

Причиной изменения подхода стала критика со стороны сообщества предыдущего механизма, когда работа с ES модулями была доступна только в файлах *.mjs. Для сохранения совместимости с CommonJS было добавлено специальное расширение *.cjs.

Разработчики Node.js пока не рекомендуют использовать ES модули в публикуемых пакетах. Релиз поддержки новых модулей без флага запланирован до выхода LTS версии Node.js 12 (октябрь 2019).

#nodejs #modules #esm #es2015

https://github.com/nodejs/node/pull/26745
Аксель Раушмайер у себя в блоге два дня назад опубликовал статью про то, как работают декларации в JavaScript — "Unpacking hoisting".

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

Традиционные функции и var'ы всплывают и работа с ними не вызывает особых проблем. Особенности есть при работе с const, let и class. Если обратиться к сущности в объявлении функции, то всё будет ок, но если попытаться выполнить эту функцию, когда сущность ещё не объявлена, то возникнет исключение ReferenceError. Промежуток времени между входом в область видимости сущности и исполнением инструкции с её объявлением называется Temporal Dead Zone (TDZ). Если в это время обратиться к объявляемым переменной/классу/функции, то возникнет исключение. Именно поэтому первый вызов функции из примера ниже выкинет исключение, а второй выполнится без ошибок:
function a() {
return b;
}

a(); // throws ReferenceError
const b = 1;
a(); // 1


Статья небольшая, но очень хорошая. Очень рекомендую почитать и поразбираться с примерами, если вы не знакомы с TDZ.

#js #es2015

http://2ality.com/2019/05/unpacking-hoisting.html
Proxy появился в ES2015, но до сих пор остаётся эзотерической фичей JavaScript. Про то чем он может быть полезен, рассказывает Томас Баррассо в статье "A practical guide to Javascript Proxy".

Proxy можно использовать для задания дефолтного значения, отличного от undefined, при обращении к несуществующему свойству объекта. С помощью него можно сделать python-like обращение к последнему элементу массива — arr[-1], скрытие свойств и инавалидирование свойств объекта, что может быть полезно при кешировании. Но больше всего мне понравился пример с перегрузкой оператора in, который позволяет реализовать проверку вхождения числа в заданный диапазон как в python 2 in range(1, 100) // true:
const range = (min, max) => new Proxy(Object.create(null), {
has: (_, prop) => (+prop >= min && +prop <= max)
})


Это, конечно, не всё, на что способен Proxy. В статье упоминается, что он лежит в основе новой системы реактивности Vue 3. Ещё там есть ссылки на другие способы использования. В общем, статья хорошая, почитать стоит.

#es2015 #js

https://blog.bitsrc.io/a-practical-guide-to-es6-proxy-229079c3c2f0
Аксель Раушмайер в прошлом месяце написал неплохую статью о том, как работают глобальные переменные в JS — "How do JavaScript’s global variables really work?"

Перед объяснением нюансов работы с глобальными переменными в статье рассказывается, что такое область видимости (scope) и как она определяется на уровне спецификации. В спеке области видимости "реализуются" с помощью lexical environments, которые состоят из environment record (нечто похожее на словарь с ключами и значениями) и ссылки на внешний scope. Таким образом дерево вложенных друг в друга областей видимости представляется деревом связанных между собой lexical environments.

На самом верхнем уровне этого дерева находится "global environment", состоящий из двух компонент: "object environment record", который поддерживает связь с свойствами глобального объекта ( window / self в браузере и global в node.js), и "declarative environment record", который создаётся с помощью const, let, class. Эти части существуют независимо, что даёт возможность создавать биндинги с одинаковыми ключами в разных записях. При обращении к таким биндингам из кода будет побеждать declarative environment record. Если очень упростить, то можно сказать, что начиная со спецификации ES2015 в JavaScript появились два разных вида глобальных переменных.

Рекомендую почитать статью и посмотреть на примеры того, как это всё работает.

#specification #js #es2015

https://2ality.com/2019/07/global-scope.html
Деструктуризация — удобное средство для доступа к свойствам объектов и элементам массивов, но оно не ограничивается только этими сценариями. Дмитрий Павлютин написал статью с описанием неочивидных подходов с использованием этой фичи — "5 Interesting Uses of JavaScript Destructuring".

1. С помощью деструктуризации можно обменивать значения переменных таким же образом, как это можно сделать в python: [a, b] = [b, a];.
2. Можно легко получить первый элемент массива с подстановкой дефолтного значения, если этого элемента нет: const [firstColor = 'white'] = colors;.
3. Комбинируя деструктуризацию с rest-оператором, можно отбросить первый элемент массива: const [, ...lastNumbers] = numbers;.
4. Деструктуризация работает для всех объектов, которые имплементируют протокол итерирования (строки, массивы, Map, Set). Например, таким образом можно получить первую букву в строке: const [firstChar] = 'cheese';.
5. Используя динамические свойства объектов, можно получить заранее неизвестное свойство объекта: const { [nameProp]: name = 'Unknown' } = obj;.

Я пересказал содержимое всей статьи, но всё равно в ней есть более развёрнутые примеры. Советую посмотреть.

https://dmitripavlutin.com/5-interesting-uses-javascript-destructuring/

#js #es2015 #list
Валерий Карпов написал статью, посвящённую Symbol — "A Practical Guide to Symbols in JavaScript".

Symbol — это новый тип данных, который появился в ES2015. Символы могут использоваться в качестве ключа объекта. Они создаются с помощью функции Symbol() и Symbol.for(), которые принимают на вход стоку-описание.

При создании символов с помощью Symbol() они гарантировано будут разными. Благодаря этой особенности можно отчётливо разграничивать пользовательские и программные данные. Например, в ES2015 символ Symbol.iterator используется для задания функции, которая будет вызываться при использовании for...of. При создании такого итератора его никто не сможет изменить по ошибке. При использовании Symbol.for('name') создаваемый символ сохраняется в глобальный реестр и становится доступен из разных мест программы при повторном вызове Symbol.for('name').

Статья небольшая, но хорошая. Рекомендую прочитать, если эта тема прошла мимо вас.

#js #es2015

http://thecodebarbarian.com/a-practical-guide-to-symbols-in-javascript.html
Никогда такого не было и вот опять. Пару дней назад в твиттере выясняли, что лучше использовать const или let.

На этот раз этот всё началось с твита Дэна Абрамова, в котором он пошутил над участниками Reddit по поводу его недавней статьи, где он предлагал использовать let. В треде он упомянул старый твит, в котором разработчики стандарта признают, что добавление двух способов для декларации переменных в блочном скоупе было ошибкой. Также в тред пришёл Аллен Вирфс-Брок — участник TC39, работавший над ES2015. Он написал, что const и let — наследие ES4, которому не придали большого внимания при переносе в ES2015. Аллен пишет, что если бы он мог это исправить, то оставил бы только const, но переименовал бы его в let. Затем в тред пришёл Брендан Айк и написал, что добавление const было вынужденной мерой, так как в некоторых движках он уже был имплементирован.

В итоге Дэн написал статью "On let vs const", где сравнил преимущества и недостатки использования eslint-правила prefer-const. Вывод простой — используйте то, что вам больше нравится.

#history #es2015 #tc39

https://overreacted.io/on-let-vs-const/
https://twitter.com/littlecalculist/status/917875241891676160
https://twitter.com/awbjs/status/1208447372910444544
Стефан Баумгартнер написал пост про тип Symbol в JS и TypeScript — "Symbols in JavaScript and TypeScript".

Symbol используется для получения уникальных значений. С помощью символов можно разграничивать библиотечные и пользовательские данные в рамках одного объекта. Но это только одно их применение. В статье разбирается пример их использования для создания подобия enum в TypeScript, который кроме типобезопасности накладывает дополнительные ограничения в рантайме после компиляции в JavaScript:
const COLOR_RED: unique symbol = Symbol('RED')
const COLOR_GREEN: unique symbol = Symbol('GREEN')
const COLOR_BLUE: unique symbol = Symbol('BLUE')
const COLOR_BLACK: unique symbol = Symbol('BLACK')

const ColorEnum = {
[COLOR_RED]: COLOR_RED,
[COLOR_GREEN]: COLOR_GREEN,
[COLOR_BLUE]: COLOR_BLUE,
}

function getHexValueWithSymbolKeys(color: keyof typeof ColorEnum) {
switch(color) {
case ColorEnum[COLOR_BLUE]: break; // good
case COLOR_RED: break; // good
case COLOR_BLACK: break; // bad
}
}


Идея интересная, но в повседневном коде наврятли стоит использовать такой подход — обычный enum выглядит более эргономично.

#js #typescript #es2015

https://fettblog.eu/symbols-in-javascript-and-typescript/