When updating Google Tag Manager to support CSP and nonce, they say to use this script:
(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');
The n&&j.setAttribute()
is confusing to me; not sure if it’s just a lack of Javascript knowledge or something else weird going on here. n
and j
are both Html Elements. setAttribute()
adds the nonce attribute to element j
and has no return value. What does the n&&
do or mean? Doesn’t this just take the "and" of element n and the return value of setAttribute? But then it doesn’t do anything with the value of that and?
Or, is it that n&&j is actually evaluated first, and this script actually calls setAttribute on both n and j? That seems like a weird behavior to me if it does.
When I paste this code into Visual Studio, it automatically adds some whitespace. I was assuming that n && j.setAttribute()
is the same as n&&j.setAttribute()
but are they actually different?
2
Answers
It’s taking advantage of short-circuiting of the boolean operators to implement a conditional in the shortest syntax. This is the result of a code minifier — they replace all the variable names with short, meaningless names and use as compact syntax as possible (including omitting any unnecessary whitespace); the code isn’t intended to be easily understood.
In this context it’s effectively equivalent to:
There’s no difference between
n&&j.setAttribute()
andn && j.setAttribute()
. Whitespace has no significance between tokens in JavaScript. The.
operator has higher precedance than&&
, so it’s always interpreted asSo VS Code was correct to reformat it that way, to make it more readable.
To get what I think you thought may have been intended, you need to add parentheses:
But that’s not what the original code was doing.
It’s just the regular old Logical AND.
This works by using the fact that JS evaluates the
&&
lazily.So if the left side is
falsy
, the right side won’t get evaluated at all (i.e.: a method there won’t be called) since the result of the binary logic operation is already clear: false.But if the left side is
truthy
, logic dictates that the right side also needs to be evaluated to get to the correct result.That the result isn’t even used doesn’t bother JS 🙂