28

I've been studying some JS libraries lately that were written by people who really knew what they were doing, and I keep seeing this pattern, and I can't find information about it. I read the docs on the .call() method, but it didn't really make sense to me. I'm hoping to get one of those good old classic in-depth SO explanations with examples.

(function(undefined){
   /*(insert entire library here)*/
}).call(this);

What is this about? Why is this a good way to write a library?

Note, sometimes the undefined is omitted, though I have no idea what difference it makes to put it there or not. I don't even know where the arguments are coming from, or who the caller is.

temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
  • 1
    @Bergi good job marking this as a duplicate, pretty sure A. it makes no difference a year later, B. my question has a way better answer than the "duplicate." – temporary_user_name Dec 08 '14 at 00:49
  • Thank you, I do this just along the way when I see a [new duplicate question](http://stackoverflow.com/q/27349669/1048572) and while searching for the canonical one I find lots of other duplicates. – Bergi Dec 08 '14 at 00:57
  • Well, okay, but I think this is the canonical one. – temporary_user_name Dec 08 '14 at 01:11
  • Hm, having a closer look at your question it's actually a duplicate not only of [self invoking anonymous function .call(this) variant](http://stackoverflow.com/q/6287511/1048572) but also of [What is the purpose of a self executing function in javascript?](http://stackoverflow.com/q/592396/1048572) (or maybe one of those linked in the comments there) and [(function( window, undefined ) { })(window) syntax?](http://stackoverflow.com/q/2716069/1048572). I think it's too broad for a canonical question. Of course, you can always cast a reopen vote in case you disagree :-) – Bergi Dec 08 '14 at 01:25
  • 3
    The answers in the first link were not as well written as @Halcyon's answer in this one. – Con Antonakos Mar 18 '15 at 17:34

1 Answers1

28

Let's disassemble this piece of code.

First off there is an anonymous function with immediate invocation. It's similar to this:

(function () {/**/}).call();
(new Date()).getTime(); // timestamp since 1970 jan 1 in milliseconds

We don't assign new Date() to a variable, instead we use it immediately.


Now why use .call instead of just ()?

.call is a method all Functions have. The first argument is what this will be bound to, subsequent arguments will be passed as arguments to the function. So:

(function () {
    console.log(this.foo); // bar
}).call({ "foo": "bar" });

This works in conjunction with undefined (see below).

.call is the same as .apply with one minor difference. .apply only takes 2 arguments, where the 2nd is an array of arguments. This would be similar:

(function () {}).call(this, "foo", "bar");
(function () {}).apply(this, [ "foo", "bar" ]);

A common use of apply is in conjunction with the magic variable arguments.

(function () {
     console.log(Array.prototype.slice.call(arguments, 1)); // [ "bar" ]
})([ "foo", "bar" ]);

Array.prototype.slice.call(arguments, 1) may look scary but really it's just arguments.slice(1), but arguments isn't an Array so it doesn't have a slice function. We borrow Arrays slice function and use .call to set the this to arguments. Array.prototype.slice(arguments, 1??) is incorrect.


Now why is there this in .call(this)? this always points to the context you're in. If you're in an instance of a class it will point to the instance and if you're in the global scope it will point to that. In a browser environment it is also window.


Why undefined? Since we did a .call(this) with no second argument, all arguments to our anonymous function are undefined. I'm not really sure why you need to make an explicit variable named undefined there. Maybe this is support for some browsers or some lint tool that likes to see undefined defined.

Thanks to @TedHopp. undefined is fickle.

var undefined = "foo";
console.log(undefined); // undefined

(function (undefined) {
    console.log(undefined); // "foo"
})("foo");

You can just as easily have:

(function () {
    /* code here */
}());

This is completely valid and works just the same. There might be some performance or linting benefits to use the form you posted.

temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
Halcyon
  • 57,230
  • 10
  • 89
  • 128
  • 6
    This is exactly why I love stack overflow. – temporary_user_name Sep 23 '13 at 23:13
  • Really nice answer. My guess is that `undefined` in the argument list guarantees that `undefined` will have its original (lack of) value. This would insulate the code from strange contexts where `undefined` had been bound to something. – Ted Hopp Sep 23 '13 at 23:17
  • To my knowledge `undefined` is always declared (but not defined). Trying to do: `var undefined = "foo"; "foo" === undefined;` gives `false`, but maybe not in all browsers. I would expect `var undefined = "foo";` to throw an Error of some sort, to elevate `undefined` to a reserved keyword, maybe this is coming in newer (stricter) ES versions. Your link points to the ES5 spec whereas this code is written to deal with – Halcyon Sep 23 '13 at 23:20
  • `undefined` is a type, but also a global variable `window.undefined`. `typeof window.undefined` retrieves `undefined`. You use `undefined` as an argument to ensure that `undefined` is really undefined in all browsers and declares it if there's any required by some lint tool as @FritsvanCampen has already said. – Roy Miloh Sep 23 '13 at 23:28
  • 1
    @RoyMiloh - The identifier `undefined` can be locally bound: `function foo(undefined) { console.log(typeof undefined); } foo(3);` will print `number`, not `undefined`. Note that `typeof window.undefined` is the _string_ `'undefined'`. According to the [ECMAScript spec](http://www.ecma-international.org/ecma-262/5.1/#sec-4.3.10), the type is `Undefined`; it's sole value is `undefined`. In ECMAScript 5, the `undefined` property of the global object is not writable; this behavior first appeared in Firefox 4 (don't know about other browsers). – Ted Hopp Sep 24 '13 at 03:56
  • `Array.prototype.slice.call` will always look scary – trickpatty Feb 03 '16 at 19:29