Это продолжение статьи, которую я написал несколько месяцев назад, « Назначение внутри условия» , в которой я описал методику назначения и оценки переменных в одном выражении и продемонстрировал ее использование для получения и обращения к узлам 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