Как стать автором
Обновить

Комментарии 16

Я сильно извиняюсь перед теми, кто уже успел прочитать статью. Дело в том, что уже опубликовав я обратил внимание, на то, что при использовании let объявлений, просадка в скорости оказалась сильнее чем в случае с var, особенно в FireFox. Соответственно я внёс в статью соответствующую отсылку на данный факт и изменил 3-ий пункт выводов, так как, с учетом этого обнаруженного нюанса в случаях необходимости использования переменных с глобальным контекстом вариант с var видится предпочтительным. Спасибо!

Напомню, что браузер называется Firefox, а не FireFox. Это название животного.


И стандарт ECMA читать не обязательно. Он написан для разработчиков интерпретатора. Простым смертным подойдут более простые определения, хотя бы из MDN.


Я бы не стал делать выводы по результатам одного простенького примера. JIT — это такая загадочная штука, что буквально смена строк местами может повернуть производительность с ног на голову. Причем в разных версиях одного браузера может быть по разному. В моем проекте замена var на let и const давала в разных браузерах противоположный результат.


Конкретный пример, в котором у Firefox выполнение увеличилось до 30 сек, можно закинуть в Bugzill-у.

Спасибо, название браузера подправил.

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

По поводу выводов относительно простенького примера. Исходя из нескольких прогонов в разных конфигурациях, которые приведены в статье, очевидна корреляция между количеством обращений к переменным в глобальной области видимости и соответствующим снижением производительности. Я проверял помимо этого еще на Watefox'е, и, во всех трёх браузерах была результаты согласовывались. И, да в Watefox'е тоже было больше 30 секунд, и, я понимаю, что он является форком Firefox.

Кроме того, именно простота этих примеров позволяет увидеть «чистую» производительность при проведении самых простых операций, которых подавляющее большинство. Однако, не спорю, в каких-то более экзотических ситуациях возможно результаты будут иные, но я надеюсь, что выводы полученные из данной статьи, помогут лучше сориентироваться в них.
хотелось бы услышать про такое:
есть
<div id='xxx' ></div>

возможны 2 варианта:
xxx.innerHTML='bla-bla';

и
var/let  d;
d = document.querySelector('#xxx');
d.innerHTML='bla-bla';


который из них предпочтительнее и почему?
и ведь возможно
var xxx=333;

я ни где не встречал предупреждения о том, что id и глобальные переменные не должны пересекаться
Дэвид Флэнаган — JavaScript. Подробное руководство (6-е издание) — 2012
14.7. Элементы документа как свойства окна

Если для именования элемента в HTML-документе используется атрибут id и
если объект Window еще не имеет свойства, имя которого совпадает со значением
этого атрибута, объект Window получает неперечислимое свойство с именем,
соответствующим значению атрибута id, значением которого становится объект HTMLEle-
ment, представляющий этот элемент документа.

Как вы уже знаете, объект Window играет роль глобального объекта, находящегося
на вершине цепочки областей видимости в клиентском JavaScript. Таким
образом, вышесказанное означает, что атрибуты id в HTML-документах становятся
глобальными переменными, доступными сценариям. Если, например, документ
включает элемент />, на него можно сослаться с помощью
глобальной переменной okay.

Однако важно отметить, что этого не происходит, если объект Window уже имеет
свойство с таким именем. Элементы с атрибутами id, имеющими значение
«history», «location» или «navigator», например, не будут доступны через глобальные
переменные, потому что эти имена уже используются. Аналогично, если HTML-
документ включает элемент с атрибутом id, имеющим значение «х» и в сценарии
объявляется и используется глобальная переменная х, явно объявленная переменная скроет неявную переменную, ссылающуюся на элемент. Если
переменная объявляется в сценарии, который в документе находится выше
именованного элемента, наличие переменной будет препятствовать появлению нового
свойства окна. А если переменная объявляется в сценарии, который находится ниже
именованного элемента, первая же инструкция присваивания значения этой
переменной затрет значение неявно созданного свойства.


var/let d;
d = document.querySelector('#xxx');
d.innerHTML='bla-bla';

Этот вариант предпочтительней (безопасней), поскольку, если где-то в вашем коде будет объявление var переменной с таким же именем как значение id глобальная переменная xxx уже не будет ссылаться на html элемент.
Этот вариант предпочтительней (безопасней), поскольку, если где-то в вашем коде будет объявление var переменной с таким же именем как значение id глобальная переменная xxx уже не будет ссылаться на html элемент.

с этим понятно. в общем — что и следовало ожидать.
но если отвлечься от такой безопасности(будем считать что прогер за этим следит), получается, что уже есть глобальная переменная с именем = id, есть ли смысл заводить новую переменную? ведь если часто идёт обращение к элементу через document.querySelector('#xxx'), то рекомендуют использовать переменную. зачем? ведь уже есть она?
остался вопрос о скорости (раз сравнивается скорость let и var).

Сделайте выборку из dom один раз. Можете даже в глобальную переменную его записать. Это будет лучше чем использовать описанное поведение

но когда назначается id элементу это уже есть определение глобальной переменной. вопрос в том — зачем дублировать?
На счёт скорости: самое быстрое, как вышло из статьи — использовать локальные переменные, не важно let или var. А созданная ссылка xxx глобальная, то есть, если вопрос только в быстродействии — надо опять же использовать

var/let  d;
d = document.querySelector('#xxx');
d.innerHTML='bla-bla';

только в локальном контексте.

Но если вопрос не в скорости и, если отвлечься от безопасности, как вы предлагаете, и есть большое желание/необходимость пользоваться именно глобальной переменной, то тогда да, смысла делать отдельную выборку и заводить новую переменную нет.
я пришёл к этому же мнению, хотелось подтверждения со стороны.
тогда, уж если ловить блох в скорости, то
в локальном контексте делать
var/let  d;
d = xxx;
d.innerHTML='bla-bla';
Присваивание d = xxx не самое верное решение, лучше сделать выборку. Так как, при взгляде не код не понятно, что из себя представляет эта самая переменная xxx (что создаёт проблемы для сопровождения), кроме того, опять же проблемы с безопасностью.

В современном вебе, с модулями и вебпаками, задефайнить что-либо в global ещё нужно постараться. Если запускали тесты в консоли devtools, то в них используется eval со своими особенностями.

Спасибо за комментарий.

Возник один вопрос: что вы имеете в виду, под особенностями eval в devtools? Разве при открытии консоли браузер начинает как-то по другому обрабатывать скрипт?
Статья была ещё раз обновлена.

Добавлена проверка на то, влияет ли только чтение (без записи) глобальных переменных на производительность. Оказалось, что нет. Выводы также соответствующим образом скорректированы.

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

Спасибо!

Про опечатку в стандарте. LexicalDeclaration само по себе заканчивается на ;. Вот здесь: LexicalDeclaration.

Похоже вы правы. Я когда смотрел ориентировался на соседнюю инструкцию — обратил внимание на for с var

for(varVariableDeclarationList;Expression;Expression)Statement

— здесь есть точка с запятой, при этом если посмотреть на VariableDeclaration, там тоже есть точка с запятой, но я похоже ошибся, так как если взглянуть именно на VariableDeclarationList её там уже нет и значит всё верно. В общем, отталкиваясь от синтаксиса for при var я неверно сориентировался в пунктуации, если коротко.

Спасибо за ценное замечание, статью поправил.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории