Статьи

(Подробнее) Назначение в условиях

Это продолжение статьи, которую я написал несколько месяцев назад, « Назначение внутри условия» , в которой я описал методику назначения и оценки переменных в одном выражении и продемонстрировал ее использование для получения и обращения к узлам DOM .

Хотя многие из вас считали, что синтаксис слишком запутан, чтобы его стоило использовать; что это просто делает для кода, который слишком трудно читать:

if(summary = document.getElementById("post-summary")) { return summary.innerHTML; } 

У меня есть определенное сочувствие к этой точке зрения; но не очень, потому что конечный результат — выражения, которые меньше кода , обычно быстрее * и могут сэкономить память (три главных цели оптимизации!)

Продолжайте независимо

Таким образом, в течение последних нескольких месяцев я экспериментировал с этой техникой, довольно специально, ища ситуации, где она могла бы быть применимой и полезной. Я придумал пару новых вариантов использования, которые, казалось, работали довольно хорошо; но я также продолжал видеть проблему, которую в конечном счете нельзя было игнорировать (на что на самом деле указывал один предыдущий читатель) — проблема заключается в переменной области действия и неоправданном создании глобальных переменных .

Избегание создания глобалов

В приведенном выше примере кода выражение создало переменную с именем summary ; но объявлению переменной не предшествует var var , и не может быть в этом контексте:

 if(var summary = document.getElementById("post-summary")) 

Это просто выкинет ошибку из-за неверного синтаксиса.

Но без предшествующего var var мы создали глобальную переменную из-за неявного глобального поведения JavaScript (т. е. любой переменной, которая явно не объявлена ​​с помощью var var создается как глобальный). Если мы уже объявили переменную в другом месте, то это не проблема. В противном случае, мы должны сначала объявить это; но если мы должны сделать это отдельно, перед условием присваивания, то мы подорвали некоторые из значений ярлыка синтаксиса!

Итак, в конце концов я просто объявил заранее кучу переменных , которые затем можно использовать где угодно, при условии, что их область действия ограничена. Неважно, где вы это делаете, если они инкапсулированы и доступны там, где они вам нужны — если вы работаете внутри шаблона класса или модуля , то верхняя часть его закрытия будет казаться очевидной место. Я заканчивал тем, что снова и снова использовал одни и те же имена переменных, где бы мне ни понадобились временные переменные, чтобы использовать этот синтаксис; и, повторно используя их, вместо того, чтобы каждый раз создавать новый, я в конечном итоге смог сэкономить больше памяти .

Кронштейны, содержащие назначение

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

Это дает нам новые возможности — назначить значение, а затем выполнить произвольную оценку для этого значения:

 if((foo = bar) > 0) { //foo is greater than zero } 

Переменная bar в этом примере также может быть возвращением из функции, и сохранение ее позволяет нам снова работать с этим значением в условии:

 if((foo = getFooValue()) > 0) { alert(foo + " is greater than zero"); } 

Это особенно полезно как способ сохранения ярлыков для длинных ссылок на свойства, которые в конечном итоге ускоряют выполнение кода, так как требуется меньше обхода объекта:

 if((foo = this.prop.subprop.childprop.value) > 0) { alert(foo + " is greater than zero"); } 

Сохранение выполнения регулярного выражения

Используя этот синтаксис, мы можем — выполнить поиск шаблона регулярного выражения в строке, сохранить массив совпадений и оценить результат — все в одном выражении (примечание. exec является методом RegExp и возвращает либо массив совпадений или null если совпадений не было):

 if(matches = /^([az]+)[:](.*)$/.exec(data)) { alert("The key is " + matches[1] + " and the value is " + matches[2]); } 

В этом примере мы полагаемся на тот факт, что null оценивается как false а массив совпадений — true , и в этом случае это безопасное предположение. Но, тем не менее, нам не нужно этого делать — мы можем заключить все это в скобки и затем провести строгую оценку:

 if((matches = /^([az]+)[:](.*)$/.exec(data)) !== null) { alert("There are " + matches.length + " matches"); } else { alert("There are no matches"); } 

Продолжай — не теряй голову!

Я буду первым, кто признает, что этот синтаксис выглядит немного странно и, следовательно, несет в себе возможность путаницы и недопонимания. Но тогда, это верно для бесчисленных вещей (сначала), а не причина для их отбрасывания; как и все остальное — со временем это становится привычным. И то, что он может предложить, на мой взгляд, намного перевешивает, что это стоит:

  • То, что он предлагает, — оптимизация — реальная проблема, которая затрагивает всех наших пользователей.
  • То, что это стоит, является некоторой читабельностью — абстрактная проблема, которая затрагивает только нас

Я не знаю о вас, но я бы назвал это сделкой!

Миниатюра кредит: sbwoodside