Fred Collins
Fred Collins

Reputation: 5010

JavaScript piece of code explanation

Check out this piece of JavaScript code:

(function (w, d) {
    var loader = function () {
        var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0];
        s.src = "https://example.org/script.js";
        tag.parentNode.insertBefore(s,tag);
    };
    w.addEventListener ? w.addEventListener("load", loader, false) :
                         w.attachEvent("onload", loader);
}) (window, document);

Why did the author of this code use this method to include a script in the document? And what is the usefulness of the line:

w.addEventListener ? w.addEventListener("load", loader, false) :
                     w.attachEvent("onload", loader);

Last point: I'm a JavaScript beginner, what is the (window, document) at the end?

Upvotes: 2

Views: 285

Answers (10)

BlindWanderer
BlindWanderer

Reputation: 116

The following addEventListener line is to register the function so that it gets called when the page finishes loading. Internet Explorer and Firefox (et al) use different functions to do this.

w.addEventListener ? w.addEventListener("load", loader, false) :
                 w.attachEvent("onload", loader);

In javascript a function is an object in and of itself. As such it's 'value' can be assigned to a variable or consumed immediately. To consume it immediately it must be wrapped in parentheses (otherwise it won't do what you want) and then call it like it were a regular function.

(function (w, d) { ... }) (window, document);

It's more obvious what is going on if we break it up across two lines.

var a = function(w, d){ ... };
a(window, document);

It was done this way to as to not pollute the global scope with temporary values or functions. Not to mention not trashing anyone else variables. This can be broken into two parts:

  1. By encapsulating the code in a closure anything explicitly declared inside is in the closure's scope, not the global scope. var loader is in the closure's scope.
  2. By consuming the closure immediately it won't be stored in a variable in the global scope. Since it was declared anonymously it won't exist as a named function in the global scope.

Upvotes: 2

Ricardo Souza
Ricardo Souza

Reputation: 16456

I may be wrong, but this is the implementation used by Google with their analytics script.

This is called a closure, a function that is autoexecuted and enclose the variables inside, so they can't mess with your code.

This codes essentially creates a script tag and append this to the DOM before the first script tag it finds in the document.

The answer for the first question is about browser compatibility. some browsers use addEventListener and others attachEvent to attach events to elements in the page (in this case, the window) and it will lounch on the load event of the window (when all content is loaded, after the document is ready). Take a look at this for a more detailed answer: window.onload vs $(document).ready()

The second answer is simple. This are the parameters used in the closure (the auto calling function) and can be read in this way:

function anonymous(w, d) {
    ...
}
anonymous(window, document);

Upvotes: 1

ctt
ctt

Reputation: 1435

The window, document at the end of the first block of code are arguments to the anonymous function defined in the rest of the code block. Since Javascript is pretty much a functional language programmers are allowed to define these anonymous functions and even use them without giving them a name.

The block of code you pasted with the question mark is an example of infix notation, a language construct that fits this pattern: condition ? ifTrueExpression : ifFalseExpression. Where condition is true, the entire expression will be equal to ifTrueExpression. Otherwise, the entire expression will be equal to ifFalseExpression.

The use of infix notation you pasted is common in detecting which type of internet browser is being used. Although, I'm not sure which browser this block of code is trying to detect, its intent is to implement an event handler in a browser specific way.

Upvotes: 1

M.Babcock
M.Babcock

Reputation: 18965

This is effectively the same as:

function RegisterEventListener(w, d) {
    var loader = function () {
        var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0];
        s.src = "https://example.org/script.js";
        tag.parentNode.insertBefore(s,tag);
    };
    if (w.addEventListener) {
       w.addEventListener("load", loader, false);
    } else {
       w.attachEvent("onload", loader);
    }
}

RegisterEventListener(window, document);

The only real differences are:

  1. If you define an anonymous function (using function () {};) without assigning it to anything it is only available for limited use (because there is no way to reference it). At the same time, anonymous functions also allow immediate execution (like the one in the code from your question function(a, b) {}(a, b);.
  2. The condition ? true : false (tertiary operator) is just shorthand for writing simple if statements so it requires less typing to write out, but some people also see it as being less readable.

Upvotes: 1

Mike Ruhlin
Mike Ruhlin

Reputation: 3556

  1. Adding the script that way allows the author to include that script in the document without directly editing HTML files. Can also be used to dynamically load a script only when needed. (i.e. if you have a bunch of code to edit something on the page, you don't want to download it until the user actually clicks the edit button, so you don't waste bandwidth when it's not needed).

  2. addEventListener and attachEvent are ways to trigger a function to be called when the page has finished loading. In this case, there's a function named loader The reason for both is that some browsers support one and some support the other. I've been using jQuery long enough that I don't remember which is which.

  3. (window, document) is a way to encapsulate those variables in scope and/or refer to them by shorthand w and d. The author is creating a function that expects those parameters, then passing both window and document as the arguments for them.

The closure also helps the author keep from having his script clash with other scripts on the page. Think of every variable declared in there like it's a private variable in other languages.

Upvotes: 1

jamesmortensen
jamesmortensen

Reputation: 34038

The author of this code is using an anonymous function wrapped in a closure to fire off the function, which registers a load event. The script on the page will not actually be loaded until the window's onload event fires.

The reason that the author may be delaying the script load may be to give the web page more time to render before actually loading in the other script. This is a great technique to load page content quickly while delaying the loading of resources that are not immediately needed.

The technique the author is using is an anonymous function wrapped in a closure. Picture this:

myFunction (window, document);

Now, I'm going to replace the function call with an anonymous function:

function(w, d) {
    // do stuff
    alert("w = " + w); 
    alert("d = " + d);
}

Now I'm going to cause that function to run immediately, without actually giving it a name. I'm also going to pass two parameters into that anonymous function:

( function(w, d) {
      // do stuff
      alert("w = " + w);
      alert("d = " + d);
})  ("1234", "5678");

The output in this example would be:

w = 1234
d = 5678

If you watch the parentheses and match them up, the first outer parentheses matches the closing parentheses on the last line at character 2, that is the function name, and the following set of parentheses wrap the two values passed into the function as parameters.

This can be a tough concept to grasp at first; after you see it done a few times, it starts to make more sense.

Upvotes: 1

d2kagw
d2kagw

Reputation: 807

So the function is wrapped in a closure. Which in turn means w = window and d = document.

When the method is called the it creates a function called loader which is the callback for one of the two possible event listener triggers (meaning, that'll be called when the load or onload event is called on the window).

The x ? y : z syntax is a shorthand if then else call.

If we expanded that out, it'd look like this:

if (w.addEventListener) {
  w.addEventListener("load", loader, false);
} else {
  w.attachEvent("onload", loader);
}

that statement is used cater the method for both IE and other browsers.

Upvotes: 1

Thanh Nguyen
Thanh Nguyen

Reputation: 161

Firstly, w.addEventListener ?to make sure if the browser supported the addEventListener method of window

Secondly, (window, document) is just parameter call of anonymous function he wrote before function(w,d) {}

Upvotes: 2

tau
tau

Reputation: 6749

It looks like the author is waiting for the page to be fully loaded before attaching the script tag. addEventListener (DOM level 2) and attachEvent (Microsoft stuff) are more flexible ways of attaching events. The code is similar to saying w.onload = loader.

The last bit is passing arguments into the anonymous function, where they are named w and d. By putting the () at the end, the anonymous function is invoked right away.

Upvotes: 1

James Montagne
James Montagne

Reputation: 78650

The first question, the code checks to see if window.addEventListener is defined. If it is, it uses it, otherwise it uses window.attachEvent. This is for browser compatibility.

The 2nd question, this code is an anonymous function which takes 2 parameters, w and d. This function is immediately called, passing the parameters window and document.

Upvotes: 3

Related Questions