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?
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:
if (n) {
j.setAttribute(...);
}
There's no difference between n&&j.setAttribute()
and n && j.setAttribute()
. Whitespace has no significance between tokens in JavaScript. The .
operator has higher precedance than &&
, so it's always interpreted as
n && (j.setAttribute())
So 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:
(n && j).setAttribute()
But that's not what the original code was doing.