Skip to content

Instantly share code, notes, and snippets.

@raganwald
Last active December 18, 2015 23:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raganwald/5859117 to your computer and use it in GitHub Desktop.
Save raganwald/5859117 to your computer and use it in GitHub Desktop.
This morning's "I made my very own WTF!?"
// I'm in the middle of a method, and I decide that I'll use an
// Immediately Invoked Function Expression ("IIFE") to create a new
// block scope so that I don't have to pollute the entire thing with
// resultJSON and contentJSON variables that would otherwise get
// hoisted.
//
// The current object DOES have a toJSON method, and so does the object called content.
// _.isFunction(this.toJSON) ==> true
// _.isFunction(content.toJSON) => true
return (function () {
var resultJSON = this.toJSON(),
contentJSON = content.toJSON();
_.each(contentJSON, function (contentRow, rowIndex) {
var resultRow = resultJSON[extant + upperLeft.y + rowIndex];
_.each(contentRow, function (contentCell, columnIndex) {
resultRow[extant + upperLeft.x + columnIndex] = contentCell;
});
});
return QuadTree.fromJSON(resultJSON);
})();
// So what happens?
// TypeError: Cannot call method 'toJSON' of undefined
// Investigation reveals that the offending line is 14,
// "resultJSON = this.toJSON()"
//
// WTF!?
@raganwald
Copy link
Author

Comments, flames, instructions to go out and read a good JS book are all welcome. As are solutions and explanations :-)

@bmitchelmore
Copy link

The IIFE creates its own context when it's executed. Change the invocation from () to apply(this) and you'll be assigning the parent this scope to that function as well and things should be fine.

@latentflip
Copy link

Yeah, that. By way of example:

var foo = { foo: 'bar' };

(function() {
  console.log('outer', this);

  (function() { console.log('inner', this) })();
}).apply(foo);

//=> outer Object { foo: 'bar' }
//=> inner Window

@latentflip
Copy link

It's easily avoided in CoffeeScript with the fat arrow, but you wrote the book on it so, hey 😄

foo = { foo: 'bar' }

(->
  console.log('outer', this)

  do =>
    console.log('inner', this)

).apply(foo)

#=> outer Object { foo: 'bar' }
#=> inner Object { foo: 'bar' }

@raganwald
Copy link
Author

You folks are spot on! I changed it to .call(this), but same thing. Good eyes!!

@corydolphin
Copy link

What happens if you pass the context into your IIFE? I.E.

return (function (that) {
  var resultJSON = that.toJSON(),
      contentJSON = content.toJSON();

  _.each(contentJSON, function (contentRow, contentIndex) {
    // Lots of copying from contentJSON to resultJSON
    // ...
  });

  return QuadTree.fromJSON(resultJSON);
})(this);

@raganwald
Copy link
Author

Passing this to that works, as did:

return (function () {
  var resultJSON = this.toJSON(),
      contentJSON = content.toJSON();

  _.each(contentJSON, function (contentRow, contentIndex) {
    // Lots of copying from contentJSON to resultJSON
    // ...
  });

  return QuadTree.fromJSON(resultJSON);
}).call(this);

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