При обновлении Диспетчера тегов Google для поддержки CSP и nonce говорят использовать этот скрипт:
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;var n=d.querySelector('[nonce]');
n&&j.setAttribute('nonce',n.nonce||n.getAttribute('nonce'));f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');
n&&j.setAttribute()
меня сбивает с толку; не уверен, что это просто недостаток знаний Javascript или здесь происходит что-то еще странное. n
и j
оба являются элементами HTML. setAttribute()
добавляет атрибут nonce к элементу j
и не имеет возвращаемого значения. Что означает n&&
? Разве это не просто «и» элемента n и возвращаемое значение setAttribute? Но тогда это ничего не делает со значением этого и?
Или на самом деле сначала вычисляется n&&j, и этот сценарий фактически вызывает setAttribute как для n, так и для j? Если это так, то мне это кажется странным поведением.
Когда я вставляю этот код в Visual Studio, он автоматически добавляет пробелы. Я предполагал, что n && j.setAttribute()
— это то же самое, что n&&j.setAttribute()
, но действительно ли они разные?
Он использует преимущества сокращения логических операторов для реализации условия в кратчайшем синтаксисе. Это результат минимизации кода — они заменяют все имена переменных короткими, бессмысленными именами и используют максимально компактный синтаксис (включая опускание ненужных пробелов); код не предназначен для легкого понимания.
В этом контексте это фактически эквивалентно:
if (n) {
j.setAttribute(...);
}
Нет никакой разницы между n&&j.setAttribute()
и n && j.setAttribute()
. Пробелы не имеют значения между токенами в JavaScript. Оператор .
имеет более высокий приоритет, чем &&
, поэтому он всегда интерпретируется как
n && (j.setAttribute())
Так что VS Code поступил правильно, переформатировав его таким образом, чтобы сделать его более читабельным.
Чтобы получить то, что, по вашему мнению, могло быть задумано, вам нужно добавить круглые скобки:
(n && j).setAttribute()
Но это не то, что делал исходный код.
Спасибо! Я не собирался использовать (n && j).setAttribute(), но думал, что, возможно, именно это и делал код.
Вот что я имел в виду под «то, что, по вашему мнению, могло быть задумано».
К сожалению, неправильно прочитали это как «то, что вы, возможно, имели в виду». Я знал о логическом коротком замыкании, но мне не приходило в голову, что 1) это можно сделать между логическим значением и функцией, которая не возвращает логическое значение; или 2) что это можно сделать само по себе, без использования оператора if или присвоения результатов чему-либо. Исходя из мира C#, ни одна из этих двух вещей не разрешена.
Ни одно из значений не является логическим. n
является либо элементом, либо null
(если querySelector()
ничего не находит), а null
считается ложным в логическом контексте. Затем вы добавляете тот факт, что любое выражение можно использовать в качестве утверждения. Я не знаю C#, но в C и C++ это похоже.
Это просто обычное старое Логическое И.
Это работает благодаря тому факту, что JS лениво оценивает &&
.
Таким образом, если левая часть ложна, правая часть вообще не будет оцениваться (т. е. метод там не будет вызываться), поскольку результат операции двоичной логики уже ясен: ложь.
Но если левая часть правдива, логика подсказывает, что правую часть также необходимо оценить, чтобы получить правильный результат.
То, что результат даже не используется, не беспокоит JS :-)
Вы смотрите на минимизированный код, который предназначен для создания максимально короткой программы. Это часто приводит к использованию в языке уловок/умных сокращений, таких как сокращение оператора if/else до
&&
и других логических операторов. Переменные Javascript не могут содержать&
, поэтомуn&&j
анализируется какn && j
.