?

Log in

No account? Create an account
entries friends calendar profile Elf Sternberg's Pendorwright Projects Previous Previous Next Next
Javascript Misunderstandings - Elf M. Sternberg
elfs
elfs
Javascript Misunderstandings

In a recent post, Zisis Maras recently talked about some interesting work with overriding the prototypes for Storage/localStorage to provide key/value space for different sessions running in the same browser. For the longest time, the advice was “Don’t ever overrride the native functions or methods,” but a lot of people seem to be ignoring that advice in the post-IE 11/Chromium/Firefox era.


But one thing he said bugged me. He talked about “cloning” functions, and then said his “favorite trick” for it was _func = func.bind({}).


This is such a terrible description (and comment) that it needs a clarification. Javascript’s context management is fundamentally sound: it’s call-by-reference with strong closure guarantees. It has one problem, though: the this special variable.


When the Javascript interpreter encounters the function keyword, it builds a new function. Variables within the function can be bound, which means that they’re meaningful only within the scope of the function, and free, in which case they were meaningful when the function definition was encountered. When the function is called, those free variable retain the value they had at the moment the function was constructed1. We call the free variables the function had at its construction its context.


When Javascript was new and poorly implemented, the this variable was introduced. It was meant to provide additional context in browser-based environments; specifically, it addressed how event information was made available to the HTML-3 “onclick” attributes, which pointed to a function named in a string argument, as strings are the only thing you’re allowed in HTML. The this variable was then redefined by successive Javascript versions to describe a number of different features, including (a) the event context, (b) the global environment, (c) a local environment to which it is bound (this word is important, remember it) with the new operator. The last is how Javascript does object oriented programming.


When a function is called with new and if the object it returns has functions bound to a .prototype attribute, it is called a constructor and the bound functions are called methods, and when that object.method() call happens, .method() gets its parent object in its this variable. (If the constructor doesn’t return an object, this is returned automatically.)


In callbacks and other asynchronous operations, this can get lost. It’s not unusual in modern Javascript to define an object that has asynchronous needs (fetch data, write data, listen to DOM objects), and an asynchronous handler within the object will need access to two different instances of this: The event’s context, and the object the event is meant to modify.


Traditionally, we used to write var that = this; before the callback was defined, making that a free instance of the object, so inside the callback that became our handle to the object, while this remained the handle on the event context.


In Javascript 5, the Function.bind() function takes a function and an object, and returns a function in whith this is locked down so that if the interpreter attempts to provide an alternative within that function, it’s prevented from doing so. Since most modern event handler protocols pass the event context in as an argument to the event handler, we no longer need the event context this, and .bind() exists to make it go away (while still supporting applications written in really ancient Javascript).


This is a long-winded way of saying you never “clone” a function in Javascript, the way one might deep copy an array or an object. Instead, all you’re doing is assuring that the function has a set and unchanging1 instance of this.


Understanding this is, depending upon your point of view, either absolutely essential (as it is in my day job) or absolutely unnecessary (as it is in my personal software projects, where I use closures and hidden contexts instead). I would go with essential if you want to write Javascript professionally. But Maras’ contribution is unfortunately only going to make that understanding harder.




1This is strictly true, but since Javascript is call-by-reference, this can lead to surprises for new developers. If a free variable was an array or an object (and objects are always objects), if the contents of the object or array are changed outside the function, they’re changed inside the function as well! The free variable refers to the object or the array, and not their contents. When we say “unchanging,” we mean that the thing referring to is unchanged; not the thing referred to.

Leave a comment