Skip to content

Instantly share code, notes, and snippets.

@cowboy
Created September 13, 2011 11:29
Show Gist options
  • Save cowboy/1213629 to your computer and use it in GitHub Desktop.
Save cowboy/1213629 to your computer and use it in GitHub Desktop.
"IIFE" - It's like an IIFE, but BETTER!!! (??)
/*!
* "IIFE" - v0.2 - 9/14/2011
* http://benalman.com/
*
* Copyright (c) 2011 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
// Usage:
//
// IIFE([value, ...,] function([arg, ...]) {
// // your code goes here
// });
function IIFE() {
// Because `arguments` is mutable, we can pop its last item off, leaving
// behind the remaining arguments to be passed into the passed function.
// Because `arguments` isn't an array however, Array#pop must be "borrowed"
// from Array.prototype, and executed using call invocation.
//
// To make a long story short:
//
// Invoke the last passed argument (function) in the same context as "IIFE,"
// passing in all preceding arguments, and returning its value.
return Array.prototype.pop.call(arguments).apply(this, arguments);
}
$(function() {
IIFE(1, 2, function(a, b, c) {
assert(a, 1, "should pass arguments correctly");
assert(b, 2, "should pass arguments correctly");
assert(c, undefined, "shouldn't pass the callback");
});
var obj = {}
IIFE.call(obj, 1, 2, function(a, b, c) {
assert(this, obj, "should set context arguments correctly");
assert(a, 1, "should pass arguments correctly");
assert(b, 2, "should pass arguments correctly");
assert(c, undefined, "shouldn't pass the callback");
});
});
// My "really simply unit testing framework" (note: requires jQuery)
function assert(actual, expected, message) {
var status = actual === expected
? "OK"
: "ERROR (got " + actual + ", expected: " + expected + ") " + message;
$("body").append(status + "<br/>");
}
// USAGE: EVERYDAY
// Gross! Those passed values are impossibly far away from the function's
// arguments list. In a large module, it would be very difficult to correlate $
// and global with jQuery and this, without lots of scrolling or some kind of
// code folding or other magic.
(function($, global) {
console.log($.fn.jquery, global);
}(jQuery, this));
// With "IIFE," passed values are right next to the function's arguments list,
// which makes the module much easier to understand! Note that the above pattern
// is called IIFE, so I've just made things all the more confusing. Of course,
// since you can use IIFEs and "IIFE" interchangeably, it should be ok. FWIW,
// this article describes the IIFE pattern, so read it if you're confused:
// http://benalman.com/news/2010/11/immediately-invoked-function-expression/
IIFE(jQuery, this, function($, global) {
console.log($.fn.jquery, global);
});
// USAGE: YOU CARE ABOUT `THIS`
var obj = {a: 123};
// Same thing, except we're setting `this` inside the IIFE explicitly. It's
// even more gross than before!
(function($, global) {
console.log(this.a, $.fn.jquery, global);
}.call(obj, jQuery, this));
// Same thing, except we're setting `this` inside the IIFE explicitly. See that
// everything you care about is all in one place. Awesome!
IIFE.call(obj, jQuery, this, function($, global) {
console.log(this.a, $.fn.jquery, global);
});
@cowboy
Copy link
Author

cowboy commented Sep 13, 2011

Note: not to be confused with Immediately Invoked Function Expressions. Well, maybe to be confused with IIFEs. Ok, totally to be confused with IIFEs, because this is a little sugar to make them just a little bit easier to deal with.

Somebody please suggest a name that won't confuse the hell out of people.

Copy link

ghost commented Sep 13, 2011

❤️. Incidentally, you can make this method even smaller, if you'd like.

function IIFE() {
  return Array.prototype.pop.call(arguments).apply(this, arguments);
}

@cowboy
Copy link
Author

cowboy commented Sep 13, 2011

I thought of that, but I was afraid of possible cross-browser issues. Are there any?

Copy link

ghost commented Sep 13, 2011

I don't think so...the arguments object is mutable, even in ECMAScript 5. I'll test it more rigorously, though.

@cowboy
Copy link
Author

cowboy commented Sep 14, 2011

@kitcambridge, I created some basic unit tests which pass in every browser I cared to test (even back to IE6, Safari 3.2.1, Firefox 2.0, Opera 9.63) so I'm going to use your code. Thanks!

@jdalton
Copy link

jdalton commented Sep 15, 2011

[].pop.call(arguments).apply(this, arguments); yum!

@phloe
Copy link

phloe commented Oct 27, 2011

Very interesting! :)

Somehow I thought of AMD: group arguments to be passed into the function in an array (much like the moduleids in a require call).

function IIFE (args, func) {
return func.apply(this, args);
}

and then used:

IIFE([jQuery, this], function($, global) {
console.log($.fn.jquery, global);
});

There's a more logical grouping but the end results is not nearly as "scripty" though :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment