javascripthtmlgoogle-tag-manager

What does && in javascript mean when used on html elements?


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?


Solution

  • 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.