Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Wednesday, 16 September 2015

Automatic Semicolon Insertion

I've been recommending to people that they not rely on Automatic Semicolon Insertion for years now, and frankly wish that the strict variant had removed it. Just wanted to share the best argument for putting semicolons where they belong that I've seen in a long time:

var foo = { a: "ay", b: "bee" } (function() { console.log("Hi there"); })();

That blows up, because the opening ( in the inline-invoked function expression at the end is interpreted as the opening parentheses of a function call, with the {...} being what it tries to call. Since that's not a function, it fails with TypeError: (intermediate value)(intermediate value) is not a function.

As the lady said: Ain't nobody got time for that! Use your semicolons.

Tuesday, 29 July 2014

JavaScript's Date/Time Format Is Not ISO-8601

TL;DR JavaScript's date/time string format isn't ISO-8601. It's much simpler, covers fewer use cases, and assumes strings written without a timezone indicator are in UTC (whereas ISO-8601 assumes they're "local" time).

Update October 2014: The draft ES6 specification has changed the timezone thing so ES6 will match ISO-8601 and assume local time, and some implementations (such as V8 in Chrome) have already updated their handling to implement that change.

Details:

There's a rumor going around that the date/time format in ECMAScript 5th edition (ES5, the current version of "JavaScript") is ISO-8601. It isn't. It's a bit like it, but it isn't, and despite the spec calling it a "simplification" of ISO-8601, it's not just a subset, either; the same string can mean two different times (or even years) when interpreted in ISO-8601's format vs. JavaScript's format.

Details:

ISO-8601 is incredibly complicated; JavaScript's format is much simpler

ISO-8601 covers a very wide range of use cases, not just date/times, but spans of time, various ways of writing time, and so forth. JavaScript's format is much simpler:

  • 201405 is a valid ISO-8601 string: It refers to the entire month of May 2014. It's an invalid date/time string in JavaScript.
  • 2014-05 also refers to the entire month of May in ISO-8601; in JavaScript, it refers to May 1st at midnight UTC (omitted fields have the implied value of 0).
  • ISO-8601 has week numbers, and Here There Be Dragons: 2009-W01-1 is Monday 29 December 2008, for instance. Fortunately, JavaScript doesn't do week numbers.
  • ISO-8601 allows fractions (of any length) on the smallest time unit in the string, so 2014-07-29T02.5Z is 2:30 in the morning UTC (so is 2014-07-29T02,5Z). JavaScript doesn't allow fractions, but uses the . (only, not the ,) to separate seconds from an optional milliseconds value (which is very like allowing up to three digits of a fraction on seconds).
  • And so on. ISO-8601 covers various other kinds of time spans and all kinds of things.

So yeah, not the same thing. Why is JavaScript's so different? Probably a combination of the fact that A) ISO-8601 is difficult to parse, and B) JavaScript's Date object has no way of representing a span of time (the entire month of May, for instance).

Time Zone Differences

Update (October 2014): See above, ES6 fixes this. I guess they decided it was a bug after all.

In New York, in ISO-8601, 2014-07-29T02:37:21 means 2:37 a.m. on the 29th; but in JavaScript, it means 10:37 p.m. on the 28th. That's because the string doesn't have any timezone indicator on it. ISO-8601 says that no timezone indicator means "local time," and so the string becomes context-sensitive. JavaScript says no timezone indicator implies Z (UTC). This is a pretty big difference. 2014-01-01T01:28:55 isn't even in the same year in the two systems in New York (or about half the rest of the planet).

Why would TC-39 (the committee that steers ECMAScript) do something so bone-headed? It probably wasn't bone-headed. Remember that this didn't come in until ECMAScript 5th edition, in 2009. Most likely, engines had been parsing strings like YYYY-MM-DD in UTC for years. TC-39 couldn't just waive a wand over it and say "Thou shalt now use local time." Too much existing code would break.

My only quarrel is with the wording in the specification, which says that the format is a "simplification" of ISO-8601. "Simplification" (to me) implies "subset," as in, a string that's valid in the subset will mean the same thing in the superset. But that's not true here. They probably should have just said "It looks a bit like ISO-8601, but it isn't" and highlighted the more important differences.

Happy coding!

Wednesday, 22 January 2014

Plain JavaScript

"I want to do this with pure JavaScript, not jQuery."
"How do I do this with raw JavaScript?"
"I don't like to use libraries, I like to use vanilla JavaScript."

Enough! Using a library like jQuery (or Closure or MooTools or...) is using plain/vanilla/raw/pure JavaScript. (I mean, unless you're using CoffeeScript, TypeScript, Dart, or other such languages.) Using a library doesn't change the language you're using.

jQuery is a library, not a language. You don't write things "in" jQuery. You write things with jQuery, in JavaScript. Or with MooTools, in CoffeeScript. Or with Closure, in Dart. You get the idea.

If you want to do things in the browser without a browser library, what you're doing is using the DOM API directly. Which is to say, writing with the DOM API, in (choose your language, probably JavaScript).

This isn't just a rant about prepositions. (It is a rant, but not just a rant.) It's about understanding what you're using, and how.

Tuesday, 24 September 2013

Submitting forms programmatically

Very short one today, folks, because something surprised me: If you use jQuery to submit a form programmatically, it will trigger submit handlers on the form. This surprised me because if you use the DOM to do it, it doesn't. Consider this HTML:

<form id="theForm" action="http://blog.niftysnippets.org" target="_blank" method="GET"> <p>This one will trigger the submit handler:</p> <input type="submit" value="Click to send form normally"> </form> <p>So will this one (which surprised me):</p> <input type="button" id="jQuerySubmit" value="Click to use jQuery to send the form"> <p>This one won't (standard DOM behavior):</p> <input type="button" id="domSubmit" value="Click to use HTMLFormElement#submit to send the form">

And this code (below the above in the HTML file):

$('#theForm').submit(function() { alert("jQuery submit handler called"); })[0].onsubmit = function() { alert("DOM submit handler called"); }; $("#jQuerySubmit").click(function() { $("#theForm").submit(); }); $("#domSubmit").click(function() { $("#theForm")[0].submit(); });

Clicking the jQuerySubmit button triggers the handlers, clicking the domSubmit button does not. Live copy

So if, like me, you're used to that handler not getting called when you submit programmatically, well, jQuery changes that! If you want the old behavior, use the DOM directly (it's only three more characters :-) ).

Happy coding!

Wednesday, 15 May 2013

Private properties in ES6 -- and ES3, and ES5

Please note: ES6 changed markedly after this article was written in 2013; what was finalized and released as ES2015 in 2015 does not have private properties after all. The concept of the "private Name" object morphed into Symbol which was similar, but different, and in particular the idea that they would be non-discoverable was dropped. (Symbols are entirely discoverable, for instance with Object.getOwnPropertySymbols.) You can have truly private per-instance information accessible even to prototype functions using WeakMap. At some point I'll rewrite the article, but the technique described herein is still valid if you don't like to just use an underscore convention or similar.

JavaScript famously lacks private properties on objects. The next version will have them (more on that below), but we can have most of the benefits of the upcoming improvement right now (without resorting to the usual hidden variables in the constructor), even on older engines. In this post, I look at what's coming, and what we can do now.

"But wait," I hear you say, "Don't we already know how to do private data, à la Crockford's Private Members in JavaScript?" Yes, but it has some downsides, not least that those members aren't actually properties, and methods shared via the prototype can't use them. A few months back, looking at the way private properties are being added to JavaScript, I was struck by how easily we can have very nearly private properties right now, today. Real properties. And of course those properties can be data properties, or methods (since methods are just data properties referring to functions). So now I'm finally getting around to writing it up.

First, a couple of terms:

  • ES3 - The version of ECMAScript (standard JavaScript) defined by the third edition specification in 1999. All major browsers support ES3.
  • ES5 - The version of ECMAScript defined by the [fifth edition specification][1] in 2011. Most modern browsers support at least parts of ES5, and many support nearly all of it.
  • ES6 - The upcoming version of ECMAScript being defined for the next specification. Early access drafts and such are available here.

The Typical Pattern For Private Information

Okay, let's start with the typical pattern for private data in classes of objects, as popularized by Crockford and others. Let's assume we have a Foo constructor and we want the objects it creates to have a hidden nifty piece of data:

function Foo() { var nifty = 42; this.method1 = function() { // Has access to `nifty` because this function // closes over it console.log("Truly private nifty info: " + nifty); }; } Foo.prototype.method2 = function() { // Does not have access to `nifty`, because this // function does not close over it. So the following // line would be an error, there is no `nifty` in scope: // console.log("Truly private nifty info: " + nifty); }; var f = new Foo(); f.method1(); // Can use `nifty` f.method2(); // Cannot :-(

nifty is truly private. Nothing has access to it but the method1 function of the object created by that specific call to new Foo. So that's great...

...but there are a few issues with this pattern:

  1. Each and every Foo object gets its own method1 function. We don't get the reuse we get with method2, where there's only one of them shared by all Foo objects via the prototype. In terms of memory impact and so on, this isn't really a big deal with modern engines unless you're creating thousands and thousands of these, since modern engines are able to reuse the code of method1 even though a new method1 object is created for each Foo object. But it's unsatisfying, and there are some development patterns that involve dynamically changing the prototype, which are obviously unable to act on method1 above, as it's not on the prototype.
  2. Different Foo objects can only see their own private data, not the private data in other Foo objects. This is markedly different from languages with true private members, and makes certain operations quite difficult.
  3. There's no way to have protected properties: If we have a Bar that inherits from Foo, there's no way for Foo objects to define things that Bar objects can see but other code cannot. (Some would argue this is a good thing, because protected data members create serious coupling between the base objects and the derived objects. But they're still quite popular in Java, C#, etc.)

...and further, just subjectively, it's clunky from a style perspective.

Truly Private Properties in ES6

With ES6, we can get truly private properties, because ES6 will have private name objects. Private name objects let you use a special kind of object as a property name, rather than a string. If you don't have access to that specific name object, you can't retrieve the property from the object.

Here's what that looks like:

// ES6 private properties (not yet available in the wild import Name from "@name"; // (Remember that this syntax is still in flux) var Foo = (function() { // Create a private name object as our private property key var nifty = new Name(); // Our constructor function Foo() { // We can just assign here as normal this[nifty] = 42; } // Methods shared by all Foo instances Foo.prototype.method1 = function() { // This method has access to `nifty`, because it // closes over the private key console.log("Truly private nifty info: " + this[nifty]); }; Foo.prototype.method2 = function() { // Also has access, for the same reason console.log("Truly private nifty info: " + this[nifty]); }; return Foo; })(); var f = new Foo(); f.method1(); // Can use `nifty` f.method2(); // Can too! :-) // Both `method1` and `method2` are *reused* by all `Foo` objects

It's just that simple. Properties created using private name objects are automatically non-enumerable, so they don't show up in for-in loops or calls to Object.keys, and code that doesn't have the specific Name object we created (nifty) cannot access that property. It is a property on the instance, but it's truly private.

So, how does this look against those issues with the typical pattern?

  1. Prototype methods on Foo objects can access the private data. Foo objects don't each have to have their own method1 as in the typical pattern shown at the top.
  2. Since all Foo code has access to the key, different Foo objects can see the private data in other Foo objects, as in Java, C#, etc.
  3. We could define Bar, deriving from Foo, in the same scoping function, which would mean it had access to the nifty name object and therefore to the nifty information in Foo objects.

Voilá! Truly private properties.

Which is great, but we don't have ES6 yet. Is there a way we can get there, or get close? Yes! We can get really close right now in ES5, and it's nearly as good in ES3.

Near-Private Properties in ES5 (and even ES3)

As of ES5, we can create non-enumerable properties (ones that are not included in for-in and don't show up in Object.keys). So those are fairly well hidden, but if whoever you're trying to keep this private from glances at the object once in the debugger, they can learn the name and use the property (and you end up with the consequent issues when you change something you considered private but which got used by the guy down the corridor anyway).

So what's the answer? Make the name different every time. Suppose we define our own Name constructor until we have ES6, and make it generate a random string of a reasonable length (and never the same string twice):

var Name = function() { var used = {}; function Name() { var length, str; do { length = 5 + Math.floor(Math.random() * 10); str = "_"; while (length--) { str += String.fromCharCode(32 + Math.floor(95 * Math.random())); } } while (used[str]); used[str] = true; return new String(str); // Since this is called via `new`, we have to return an object to override the default } return Name; }();

Now we can use the ES6 code above (minus the import statement, of course) and get really obscure properties (even in ES3), in that they have names that change every time the code runs. The guy down the corridor can look at the name in the debugger, but he can't write code relying on it, because it's always changing. Instead, he has to come down the corridor and ask you to make an API change so he can do what he needs to do, which is what he should have done in the first place.

In ES5, we can take it a step further and make the property non-enumerable so that in addition to having a random name, it doesn't show up in for-in or Object.keys. We can even do that in the same codebase by only using the ES5 feature if it's present.

Here's a complete ES3 and ES5 example, using our Name constructor from above, changes called out with *** markers:

// Nearly-private properties // ***No `import` here (once the final form is determined, we'll probably be able to feature test for it) var Foo = (function() { // Create a random string as our private property key var nifty = new Name(); // Our constructor function Foo() { // We can just assign here as normal this[nifty] = 42; } // ***On ES5, make the property non-enumerable // (that's the default for properties created with // Object.defineProperty) if (Object.defineProperty) { // Only needed for ES3-compatibility Object.defineProperty(Foo.prototype, nifty, { writable: true }); } // ***End change // Methods shared by all Foo instances Foo.prototype.method1 = function() { // This method has access to `nifty`, because it // closes over the private key console.log("Truly private nifty info: " + this[nifty]); }; Foo.prototype.method2 = function() { // Also has access, for the same reason console.log("Truly private nifty info: " + this[nifty]); }; return Foo; })(); var f = new Foo(); f.method1(); // Can use nifty! f.method2(); // Can too! :-) // Both `method1` and `method2` are *reused* by all `Foo` objects

That's it! Virtually identical to the ES6 code, and it provides nearly as good encapsulation, certainly on ES5. The property we create is not truly private, but it's really obscure (on ES5) and pretty obscure even on ES3. In ES5 it doesn't show up in for-in loops (because the property we created is non-enumerable), and even on ES3 its name changes every time the code runs. So any code attempting to use the private data must first figure out the property name, which is a non-trivial exercise (probably impossible purely in code in ES5, as that code can't get a list of the non-enumerable property names of the object). Naturally, one glance at the object in a debugger shows you the property and its value, but nothing is private from debuggers, and the name will change next time. The guy down the corridor will be forced to get up and ask you to make the information available in the API, rather than using your private data!

Hey, What About Methods?

The great thing is that there's absolutely nothing special about methods using this pattern. You want a private method? Just define it, just like you define a private data property. Because of course, JavaScript doesn't really have methods, just properties that refer to functions and a bit of syntactic sugar.

Here's an example for ES3 and ES5 that uses both a private data property, and a private method. And of course, making it ES6 instead just requires adding the import and then (optionally) removing the Object.defineProperties call:

var Greeter = (function() { var normalize = new Name(); // Private worker method key var personName = new Name(); // Private data key // Our constructor function Greeter(n) { this[personName] = n; } // Private properties if (Object.definePropertes) { // Only needed for ES3-compatibility Object.definePropertes(Greeter.prototype, { normalize: {writable: true}, personName: {writable: true} }); } // Methods shared by all Greeter instances Greeter.prototype[normalize] = function(arg) { // Okay, so this is a really boring thing for the private worker method to do var s = this[personName]; return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); }; Greeter.prototype.sayHey = function() { console.log("Hey " + this[normalize]()); }; Greeter.prototype.sayBye = function() { console.log("Bye " + this[normalize]()); }; return Greeter; })(); var g = new Greeter("JACK"); // Note the all caps g.sayHey(); // "Hey Jack" g.sayBye(); // "Bye Jack"

Happy Coding!

Wednesday, 24 October 2012

Asynchronicity

I see questions like this one a fair bit: The author has written this code (and is apparently using jQuery):

function Obj() { this.id = 0; this.name = ''; } Obj.prototype.setName = function(name) { this.name = name; }; function init() { var object1; object1 = new Obj(); object1.setName("Chris"); alert(object1.name); // alerts 'Chris' $.post('my_json_list.php', function(data) { object1.setName(data.name); alert(object1.name); // alerts 'John' }); // After completing the data transfer alert the value of object alert('After data transfer the value is: '+ object1.name); // alerts 'Chris' (!) }

The comment at the end embodies the question: The author expects the ajax call to be complete at that point. But it isn't. That code runs after the request has been started, but before it completes. So of course object1.name is still "Chris" — nothing has changed it yet. The author of that code is not remotely alone in this confusion, I've answered at least a dozen questions on StackOverflow (such as this one) where this was the fundamental problem. So:

Shout it from the rooftops: Ajax calls are asynchronous. :-) (By default.)

That means the code that starts the call runs, then any code following it, and then the ajax callbacks happen some time later. E.g., here's that init code again with some comments saying when it happens:

function init() { // 1: First this code runs... var object1; object1 = new Obj(); object1.setName("Chris"); alert(object1.name); // alerts 'Chris' // 2: ...and now this code *starts* the request... $.post('my_json_list.php', function(data) { // 4: (See #3 below) Then, some time AFTER #3 below, this code runs object1.setName(data.name); alert(object1.name); // alerts 'John' }); // 3: ...now the request has started but is not yet finished, // so `object1.name` remains `"Chris"` alert('After data transfer the value is: '+ object1.name); // alerts 'Chris' (!) }

So what to do about it? Easy, don't use the result of the call at point #3 above, use it at point #4 above.

This simple fact has an important implication: You cannot use the result of an ajax call as the return value of a function. This code is fundamentally flawed:

function getSomething(id) { var returnValue; $.ajax({ url: "/path/to/resource", data: {id: id}, success: function(result) { returnValue = result.data; } }); return returnValue; // WRONG }

That's written so you can call it like this:

something = getSomething("some ID"); if (something) { doSomethingWith(something); } else { doSomethingElse(); }

The problem is, it doesn't matter what id value you feed into doSomething, I can tell you what its return value will be every single time: undefined. The call to doSomething will complete, and return the default value of returnValue (which is undefined), and then some time later the callback will occur and set the value of returnValue (but it's a bit like a tree falling in the forest, as at that point no one uses it).

Can doSomething be fixed? Yes, in two ways: We can force the ajax call to be synchronous (bad idea) or we can embrace the event-driven nature of web applications (good idea).

Let's look at that first option: We can (for now) add the option async: false to the ajax call (that option is deprecated — but functional — in jQuery 1.8 and will go away at some point, though not apparently in 1.9). If we do that, the call to ajax doesn't return until the ajax call completes and its callbacks have finished. This is a bad idea because ajax calls can take significant time (even a tenth of a second is significant to human perception), and JavaScript on browsers is single-threaded. So during the time the ajax call takes, our page becomes non-responsive. (In fact, on several browsers, the entire browser — including unrelated tabs — just seems to lock up.)

Okay, so we don't want that. How do we fix it so doSomething can return what we want it to? By making doSomething return its result using a callback, just like ajax does:

function getSomething(id, callback) { $.ajax({ url: "/path/to/resource", data: {id: id}, success: function(result) { callback(result.data); } }); }

...and calling it like this...

getSomething("some ID", function(something) { if (something) { doSomethingWith(something); } else { doSomethingElse(); } });

Voilà, we've embraced the event-driven nature of web applications, kept our pages responsive, and it didn't even have that much impact on the calling code.

Happy (async) coding!

Thursday, 27 September 2012

Quick note on RegExp#lastIndex

Just a quick note on RegExp#lastIndex: It's misnamed. It's not the "last" index of anything, it's the index of the next character in the string that will be looked at by the regex instance's exec function (if the regex has the global flag and exec is used on a string that's long enough). It's 0 on freshly-created instances. Just useful to remember, if you ever need to set it explicitly (which you're allowed to do), think in terms of "next" rather than "last".

Of course, you hardly ever need to set it explicitly. The only reason I've ever done so was to work around a bug an issue in some JavaScript engines which are pretty outdated now (such as the one in Firefox 3.6, which virtually no one uses anymore). For anyone who doesn't already know about it, that issue was that some engines reused RegExp instances defined by literals in unexpected ways, which is a problem because RegExp instances have state (the aforementioned lastIndex). On those engines, you get surprising results from code like this:

function test(str, expect) { var re = /./g, m = re.exec(str); if (m) { console.log("Matched: " + m[0] + ", expected: " + expect); } else { console.log("No match, expected " + (expect === null ? "no match" : expect)); } } test("one", "o"); test("two", "t");

If you run that code on most engines, you get the expected results. But on some engines, instead of matching "t" on the second call to test, the regex matches "w" because the instance defined by the literal gets reused (the same instance is used by both calls to test), and of course after the first call its lastIndex is 1. The workaround was to explicitly set re.lastIndex = 0; before calling exec when you were starting a new set of matches, even if it looked like the instance was fresh.

Apparently there was some ambiguity in the spec (gosh) which makes this an interpretation rather than an outright bug, although I suspect I'm not the only one thinking it's pretty clear that two separate instances should be used. It was cleared up in the ES5 spec and Firefox's engine has been doing this right for a while now (since Firefox 4, I think). I expect any other older engines that had this odd interpretation have probably been fixed as well.

Tuesday, 14 August 2012

Measuring Scrollbar Size

Normally we want to avoid doing this sort of thing, but sometimes you just end up having no other option: Recently I couldn't avoid doing some sizing logic in JavaScript rather than CSS and markup, and I had to know the size of the scrollbars on specific elements. I found this post by Alexandre Gomes (which in turn was based on a MooTools forum thread; those forums are gone now), which shows a simple way to do it. I modified the code to measure both vertical and horizontal scrollbars and let you specify the element within which to measure in case the styling of that element affects the result, added some comments, and did some cleanup. Works a treat, I've tested it on a wide variety of browsers young and old with good results. Here's the code:

function measureScrollbars(container) { var child, parent, wWithout, wWith, hWithout, hWith; // Create a parent div with a fixed size parent = document.createElement('div'); parent.style.width = "150px"; parent.style.height = "150px"; // Create a child div that's 100% of the width (granted // that would be the default for a div) and which exceeds // the parent's height child = document.createElement('div'); child.style.width = "100%"; child.style.height = "200px"; // Put them in the DOM parent.appendChild(child); container.appendChild(parent); // Measure the width without a scrollbar, then again with parent.style.overflow = "hidden"; wWithout = child.offsetWidth; parent.style.overflow = "scroll"; wWith = child.offsetWidth; if (wWithout === wWith && "clientWidth" in parent) { wWith = parent.clientWidth; } // Now make the child 100% height, and too wide child.style.height = "100%"; child.style.width = "200px"; // Measure without scrollbar, then again with parent.style.overflow = "hidden"; hWithout = child.offsetHeight; parent.style.overflow = "scroll"; hWith = child.offsetHeight; if (hWithout === hWith && "clientHeight" in parent) { hWith = parent.clientHeight; } // Done container.removeChild(parent); return { width: wWithout - wWith, height: hWithout - hWith }; }

Or if you want the jQuery-ified version:

function measureScrollbars(container) { var child, parent, wWithout, wWith, hWithout, hWith; // Create a parent div with a fixed size parent = $('<div>').css({width: "150px", height: "150px"}); // Create a child div that's 100% of the width (granted // that would be the default for a div) and which exceeds // the parent's height child = $('<div>').css({width: "100%", height: "200px"}); // Put them in the DOM parent.append(child).appendTo(container); // Measure the width without a scrollbar, then again with parent.css("overflow", "hidden"); wWithout = child[0].offsetWidth; parent.css("overflow", "scroll"); wWith = child[0].offsetWidth; if (wWithout === wWith && "clientWidth" in parent[0]) { wWith = parent[0].clientWidth; } // Now make the child 100% height, and too wide child.css({height: "100%", width: "200px"}); // Measure without scrollbar, then again with parent.css("overflow", "hidden"); hWithout = child[0].offsetHeight; parent.css("overflow", "scroll"); hWith = child[0].offsetHeight; if (hWithout === hWith && "clientHeight" in parent[0]) { hWith = parent[0].clientHeight; } // Done parent.remove(); return { width: wWithout - wWith, height: hWithout - hWith }; }

Happy coding!

Wednesday, 8 August 2012

jQuery - Element cleanup update

For those who saw my jQuery - Cleaning up when elements go away post yesterday, I've updated it showing how we can do this right now, today, without waiting for the enhancement (or if the enhancement is never accepted). Oh, and the enhancement went from six lines to three. Many thanks to Dave Methvin for showing how (in both cases). Enjoy!

Tuesday, 7 August 2012

jQuery - Cleaning up when elements go away

(Updated 08/08/2012.)

Have you ever wanted to get a notification when an element is removed from the DOM so you could clean up? For instance, maybe you have events hooked on a different object (like resize on window) that you want to unhook when the element goes away.

Recently I wanted to, and since I know that jQuery does cleanup when elements are removed (so it can clear out event handlers and its cache for data), I wondered if it triggers an event for us.

It doesn't, but we can still get what we want quite cleanly. I'll describe what I'm hoping we'll be able to do tomorrow, and what we can do today.

Tomorrow (I hope)

We can enhance jQuery to give us an event on cleanup — with just three lines of code and virtually no overhead. Inside jQuery's internal cleanData function, just after the line that currently reads if ( data && data.events ) {, we add this:

if ( data.events.jqdestroy ) { jQuery(elem).triggerHandler("jqdestroy"); }

Boom, that's it. Now if we need notification when an element is going away, we just hook up the event:

$("selector_for_the_element").on("jqdestroy", function() { // Do your cleanup });

We use triggerHandler rather than trigger because we don't want bubbling (there's another way we can avoid bubbling, but it requires a couple more lines of code, and triggerHandler is more efficient anyway — thanks to Dave Methvin for that!).

Here's a copy of jQuery 1.8rc1 with the patch, you can play with it here — that latter link is a test page that generates 10,000 elements, 5,000 of which we hook the click event on (so that they have something in data.events), and two of which we hook the jqdestroy event on. Then we call html on the container element to destroy them all and time how long it takes. You can compare that with this version using an unmodified version of 1.8rc1. For me, the times are much of a muchness (on Firefox 14, both versions average ~142ms when the jqdestroy event isn't hooked, and when it is [on two elements] the version that fires it averages ~163ms).

What I like about this is that if nothing has hooked the event, the overhead is at most one extra property check (the if ( data.events.jqdestroy )) per element destroyed (zero overhead for elements that haven't had any events hooked at all), but it enables a completely familiar and straight-forward way to get notifications.

Well, okay, but is there really a need for it? It would seem so: jQuery UI duck-punches cleanData so they can clean up; TinyMCE goes further, monkey-patching several API calls (empty, replaceWith, and others) so it can clean up an editor attached to an element. And of course, I wanted it for my plug-in that needs to unhook window.resize if there are no more active copies of it.

Now, let me clear about something: To my mind, using this event is a last resort. It's a big hammer, and if you used it on a lot of elements, removing those from the DOM could lag a bit. Consider this example which hooks jqdestroy on 5,000 of the 10,000 elements. For me, the elapsed times go from ~163ms when firing it on just two elements to ~450ms firing on 5,000 (again Firefox 14). Now, 5,000 is a lot of elements to hook this event (or any other) on, and anything can be abused, the point is just...don't abuse it. :-) The best use cases for this will be things like TinyMCE's editors, or grid plug-ins that need to handle resize in code, that sort of thing — where there will be only a few elements with the event hooked.

I've opened an enhancement request on the jQuery Trac database for this, offering to do the patch and send a pull request if the idea has legs. If you think this is a good idea, your support would be welcome! I'm not saying we have to do it the specific way I've outlined in this post, I'm totally open to other ways to get there. Three lines of code, near-zero overhead, and a familiar paradigm seems pretty good to me, though.

Today

But what if that enhancement doesn't get adopted? Or if we need to do this right now, today, with the current version of jQuery? Do we have to hack the jQuery file, or resort to monkey-patching?

Nope. In the linked Trac ticket, Dave Methvin showed how we can do it today, by adding our own "special" event and watching for the teardown on it. This uses the event system, but we'll never actually receive the event in the normal way. Here's how it works:

First, we create a "special" event:

$.event.special.ourowndestroy = { teardown: function() { // Handle it here, `this` is the element being clean up console.log(this.id + " being destroyed"); } };

Then we force that to occur by hooking the event on the element, even though our handler will never get called:

$("selector_for_the_element").on("ourowndestroy", function() { // This is never called });

Here it is in action using jQuery 1.7.2.

I've put a function there to make the point that the handler is never called (the action is in the teardown function); in reality I'd probably use $.noop or just false (shorthand for a handler that does return false) instead.

Now, when an element is being cleaned up, our teardown function will get called with this pointing at the element in question. Note that if we didn't hook the event on the element, we wouldn't force the teardown, so even though our handler isn't called, that's required.

Note: You'll also get the teardown call if you remove the event handler from the element (and then not when it's cleaned up, as it's not on there anymore), so if you're using this mechanism, either never remove the handler or handle the fact you get the call if you do.

So that's not an ideal way to do it, and it's not the way this stuff is normally done, but it's a passable workaround in the short term — and much better than monkey-patching jQuery's API on the fly.

Happy coding!

Thursday, 2 August 2012

Steve Sanderson's Round-Up of Eight Rich JS Libs/Frameworks

Steve Sanderson's done an interesting round up of the eight libraries and frameworks represented at the Throne of JS conference recently. The conference was about JavaScript applications, not web pages, and focuses on the kinds of projects that help you do your Model-View-Whatever stuff. Worth reading, bookmarking, and re-reading later. Steve declares his interest — he's on the KnockoutJS core team — but keeps it neutral, partially by staying very high-level. Which is exactly what I want from this kind of round-up.

Saturday, 7 July 2012

Well, I'm floored

How do you floor (or truncate) a floating-point number in JavaScript? (E.g., take a value like 5.7 and get just the 5?). The answer is simple: Use Math.floor. That's the right answer at least 99.99% of the time. It's clear, straightforward, easy to read, easy to maintain. It does what it says on the tin:

console.log(Math.floor(5.7)); // "5"

Sorted.

But you see people doing other things in the name of "performance," which is the purpose of this post: Primarily, to explain what they're doing; and also to see how much actual benefit they're getting from it.

Why performance? On rare occasions, you may have an operation where you need to squeeze every last bit of performance out that you can. The theory here is: Function calls are cheap, but they aren't free, and unless the JavaScript engine you're using does static analysis of your code, when call Math.floor it has to look up the Math identifier (which means walking the scope chain to see if it's been shadowed, before ultimately finding it at the outermost level, the global object), look up its floor property, and then call the function that property points to. So if there's a more direct route, people want to take it when they're looking for every last cycle.

And what they turn to is bitwise operations. JavaScript only has floating-point numbers, of course, but its bitwise operations are defined in terms of 32-bit integers. So when you apply those operations to a number, the first thing that happens is that the number is turned into an integer (whole number) by just chopping off any fractional part (see the internal ToInt32 operation for details). Chopping off the fractional portion is, of course, floors the number — exactly what we want. (Well, with a caveat: The bitwise operators "floor" positive numbers, but they "ceil" negative numbers. "Floor" always goes down, and of course for negative numbers "down" is away from zero rather than toward it; so Math.floor(-12.1) is -13, not -12. When you just chop off the fractional part like the bitwise ops do, you get -12 instead.)

There are lots of operations to choose from that will floor the number without actually changing its value; I'll list them in rough order of how often I've seen people use them:

  • Double bitwise NOT: ~~num
  • Bitwise OR with zero: num | 0
  • Left bitwise shift, but not really shifting: num << 0
  • Right bitwise shift, but not really shifting: num >> 0
...and there are also these, which I've never seen anyone actually use as they're a bit clunkier than the above:
  • Unsigned right bitwise shift, but not really shifting: num >>> 0
  • Bitwise AND with all-bits-on: num & 0xFFFFFFFF
  • Double bitwise XOR with zero: num ^ 0 ^ 0 (or indeed, any other number, but zero is easy to type)

But do they really go faster? As always, it depends on what engine you're using:


Figure 1 Math.floor vs. the bitwise operators
(click image for full-size version)
(interactive version on jsperf)

(Compare only the operations on the same browser; the different browsers were run on different machines, so their speed can't be usefully compared with each other.)

The first take-away from that chart is: Things ain't like they used to be. It used to be that the bitwise operators were a lot faster than Math.floor. But engines have really stepped up their game in terms of scope chain resolution speed and function call overhead/inlining. (To give you an idea: IE7 does the bitwise OR with 0 nearly nine times faster than Math.floor, much more dramatic than any of the results above.)

The second take-away is: On most engines, yes, the bitwise operators are faster than Math.floor, either very slightly faster, or markedly faster. The outlier here is Firefox 3.6, which must have some specific Math.floor optimization as it screams past the bitwise operators. More recent versions of Firefox don't show that behavior.

The third take-away is: All bitwise operators are not equal. Looking at the chart, the best on most engines is the bitwise OR with zero (num | 0; the bright red lines) — unless you're using Safari. The most reliable all-rounder (performs well across engines, even if not in first place most of the time) is, oddly, the signed right-shift (num >> 0; the reddish-pink, second from the bottom of each grouping).

And finally, we can't tell this from that chart per se, but it's worth noting that using the bitwise operators tends to give you the greatest benefit on the slowest engines; e.g., there's not much in it on recent Chrome or Firefox, but there's a much larger difference on the slower IE8, IE9, Opera, and Safari engines (again, Firefox 3.6 seems to be the outlier here).

So if you've been wondering what that n = n|0 was doing in that code you saw, now you know; it's chopping the fractional part off n — either for performance reasons, or because the coder wanted 12.7 to become 12 and -12.1 to become -12 rather than -13. And it looks like, in those very rare situations where it matters, you do actually get a performance benefit where you need it using the more-obscure, but faster bitwise operation to get the job done. My recommendation: Just be sure to comment what you're doing. :-)

Happy Coding!

Thursday, 24 May 2012

Finally, the normative ECMAScript Spec - in HTML

Finally a normative ECMAScript specification in HTML. Very worthy private efforts notwithstanding (here, here), having a normative deeply-linkable, HTML edition is huge — and long overdue.

Wednesday, 4 April 2012

Announcing Lineage

Note: As of late 2015, I don't use Lineage anymore, there's no need. I use the class features of ES2015 (aka "ES6") instead. If my target is a browser, for now I transpile with Babel (no need when working in NodeJS, the latest Node uses the latest V8 which has solid support for ES2015).

Just a brief post to announce my latest mini-project, Lineage. It's a small, simple toolkit for creating JavaScript constructor functions and their prototypes ("classes," if you will) in a straight-forward and concise way. From the project home page:

  • Lineage's API lets you define prototypes with a very concise syntax, while still encouraging you to create functions with real names (rather than anonymous functions); this helps your tools help you (debuggers show function names in call stacks, for example).
  • Lineage provides a highly efficient mechanism for "supercalls" (calling into the parent prototype's versions of methods from an instance using a derived prototype).
  • Lineage's API encourages and supports use of the module pattern for each constructor and its prototype.
  • Lineage is small, <3k compressed (gzips to <1,500 bytes, a quarter of which is the MIT license) — because it doesn't try to reinvent inheritance, it just simplifies access to the power of JavaScript's prototypical inheritance.

Here's an example of defining a constructor called Thing with a spiffy function on the prototype:

var Thing = Lineage.define(function(p) {
p.spiffy = function() {
console.log("I'm a spiffy thing!");
};
});

...or if like me you prefer your functions to have names:

var Thing = Lineage.define("Thing", function(p) {
p.spiffy = Thing_spiffy;
function Thing_spiffy() {
console.log("I'm a spiffy thing!");
}
});

Now, with such a trivial example, that doesn't offer you much on top of the raw equivalent:

var Thing = (function() {
function Thing() {
}
Thing.prototype.spiffy = Thing_spiffy;
function Thing_spiffy() {
console.log("I'm a spiffy thing!");
}
return Thing;
})();

...and that's the point, Lineage works with JavaScript's natural inheritance, it doesn't try to reinvent things. But when you get into inheritance, and in particular start making supercalls, Lineage reduces the code markedly while ensuring everything is hooked up properly, and does so in a way that's easy to use correctly, without retyping a lot of boilerplate code.

Rather than loading up this post with code examples, I'll point you to the progressive series of examples on the Lineage Comparison with Plain JavaScript page for more.

I'm using Lineage in projects now, and so far I'm really liking the simplicity of it. I hope you will too! If you do play with it, please send comments (positive and negative!), the feedback is very welcome.

Happy coding!

Tuesday, 6 March 2012

Adding language choice to FogBugz's code snippets

Surprisingly, the "code snippet" widget used by the FogBugz wiki feature doesn't support telling the pretty-printer (they're using Google's google-code-prettify script) what language the text is in. Since the script can't always tell what language the code is in, this is a problem. And apparently, I'm the first one to ask about this. Wow.

The answer is to write a BugMonkey script and install it in your FogBugz installation. Here's my first take at it, dashed off fairly quickly but apparently functional:

name: Add language support to code snippet pretty-printing in FogBugz
description: Fixes code snipeet pretty-printing in FogBugz by adding the ability to specify a language.
author: T.J. Crowder [tj at crowder software dot com]
version: 1.0.0.0

js:

// Written by T.J. Crowder [tj at crowder software dot com]
// Licensed under the Creative Commons Attribution License 2.0 (UK)
// http://creativecommons.org/licenses/by/2.0/uk/
//
// At the beginning of each code snippet, you can optionally include a line
// defining the language, in the form:
//
// lang_xyz:
//
// This must be the first line.
//
// The script below will find these, extract the "xyz" from it, remove it and
// any line break following it, and add "lang-xyz" to the `pre` element.
// If any matches were found, when done `prettyPrint` is called to reformat
// the elements.
//
// Example:
//
// lang_sql:
// -- A comment
// CREATE TABLE [Foo] (
// [Bar] NVARCHAR(MAX)
// )
//
// ...renders without the first line, with the class "lang-sql" on the element
// so the pretty-printer knows what the language is.
//
// This code may be fairly fragile, depending on the precise workings of the pretty
// printer. It would be better BY FAR if FogBugz updated the code snippet widget to
// support specifying the language.
//
// Many thanks to Ben McCormack and Michel de Ruiter for pointing me in the right
// direction here: http://fogbugz.stackexchange.com/questions/10065
(function($) {
// Our handler
function handlePrettyLanguages() {
var changes = false;
$("pre.prettyprint").each(function() {
var pre, firstElement, span, match, lang, nextpun, nextbr;

firstElement = this.firstChild;
while (firstElement && firstElement.nodeType !== 1) {
firstElement = firstElement.nextSibling;
}
if (firstElement && firstElement.tagName === 'SPAN') {
pre = $(this);
span = $(firstElement);
match = /^\s*lang_([A-Za-z0-9_]+)\s*$/.exec(span.text());
if (match && match[1]) {
lang = match[1];
nextpun = span.next("span.pun");
if (!nextpun[0]) {
nextpun = span;
}
nextbr = nextpun.next("br");
if (!nextbr[0]) {
nextbr = nextpun.next().children().first();
if (nextbr[0] && nextbr[0].tagName !== "BR") {
nextbr = $();
}
}
pre.addClass("lang-" + lang);
span.remove();
if (nextpun !== span) {
nextpun.remove();
}
nextbr.remove();
changes = true;
}
}
});
if (changes) {
prettyPrint();
}
}

// Hook it up on page ready and when BugViewChange events occur
$(handlePrettyLanguages);
$(window).on('BugViewChange', handlePrettyLanguages);
})(jQuery);

You install that via My Settings | Customizations.

Happy pretty printing!

Thursday, 1 March 2012

Match everything...except!

Micro-post:

I was truly shocked to find today that in JavaScript regular expressions, . (the decimal point) doesn't do what I thought it did. I thought . meant "match any character." You too? Yeah. But it doesn't. Specifically, . doesn't match line terminators (so, \r, \n, \u2028, and \u2029). From Section 15.10.2.8:

The production Atom :: . evaluates as follows:

  1. Let A be the set of all characters except LineTerminator.
  2. Call CharacterSetMatcher(A, false) and return its Matcher result.

...which if you spend really quite a long time looking tells you that . matches anything but line terminators.

Maybe I'm just parading my ignorance here, but I would have thought that absent the "multiline" flag or something, . matched everything. Nope. If you want to do that, use [\s\S] (e.g., everything that either is or isn't whitespace).

Happy coding!

Tuesday, 28 February 2012

Creating a function with a true name defined at runtime

I used to have an article here showing how to dynamically create functions with true names. Except it didn't work properly on Firefox and there's a much better way (which does work properly on Firefox) described in this article by Marcos Cáceres. It looks like this:

var name = "foo"; var func = new Function( "return function " + name + "(){ alert('sweet!')}" )();

Yes, the Function constructor is basically a call to eval, so you'd only do this with input you control well. But when you need to do it, this is how.

Nice one, Marcos!

Friday, 10 February 2012

`forEach` and runtime cost

Just a tiny one today, mostly to write this down somewhere:

As you all know, ECMAScript5 adds forEach to arrays, where you supply a function that gets called for each element in the array. There are lots of benefits to this, not least variable scoping on the index and value variables and a bit less typing, but don't all of those function calls add up to a significant runtime cost?

No, they don't.

I got curious about it (I have a tendency to micro-optimize, which I'm trying to break myself of), so I tested it on the slowest (desktop) browser currently in use: IE6. Specifically, IE6 running in an old Windows 2000 VM I have lying around. I tested the performance of looping through a 100-entry array both with and without calling a function. Without the function call, IE6 looped through the array ~4,500 times in a second (that's 450,000 loop iterations/second). With the function, it managed ~2,000 times a second (200,000 loop iterations/second). So while that's a big relative difference (56% slower!), in real terms it falls into fergedaboudit territory: 2.78 microseconds of overhead. You heard, me, microseconds. That's 0.00278 milliseconds.

Now, I'm not going to say there aren't places where it could matter. I am going to say that they're going to be extraordinarily rare, I'd wager I'll never run into a situation where it makes a difference and nor will you. Whatever else you're doing in the loop body is totally going to wash out the function calls. Really.

Happy coding!

Wednesday, 30 November 2011

The true story on return false

In JavaScript event handlers, you'll frequently see return false; at the end. Why? What does it do? The answer is: It depends. Before we get into the details, there are basically two things it could be doing:

  1. Preventing the default action of the event, such as when you click a link and the browser follows it.
  2. Stopping propagation of the event to ancestor elements.

So which does return false do? Just one, neither, or both:

  • DOM0 handlers: In an old-style DOM0 handler, hooked up via an attribute like this:
    <div onclick="return functionName();">
    ...it prevents the default action but doesn't stop propagation. Note that you need that return in the attribute. Try it here.
  • DOM0 handlers (again): The same is true of an old-style DOM0 handler hooked up via the reflected property for the attribute, like this:
    document.getElementById("someId").onclick = functionName;
    Try it here. As before, return false; prevents the default action but doesn't stop propagation.
  • DOM2 handlers: In a proper DOM2 handler hooked up via addEventListener, like this:
    document.getElementById("someId").addEventListener("click", functionName, false);
    ...return false does absolutely nothing. Instead, use the preventDefault and stopPropagation functions on the Event object your handler receives as an argument. Try it here (be sure to use a non-Microsoft browser, or use IE9 or higher).
  • Microsoft DOM2-ish handlers: In a DOM2-ish handler hooked up with Microsoft's attachEvent function, like this:
    document.getElementById("someId").attachEvent("onclick", functionName);
    ...return false prevents the default but not propagation, just like a DOM0 handler. Try it here (using IE8 or lower).
  • jQuery handlers: Event handlers hooked up with jQuery get a twofer: return false both prevents the default and stops propagation. It's a jQuery thing.

Happy handling!

Sunday, 22 May 2011

Appending to an array

JavaScript's Array#concat function is handy and cool, but it creates a copy of both arrays. That is, given array a and array b, a.concat(b) will create a third array c with the contents of both of them, leaving a and b intact. Now, sometimes that's what you want, but other times you just want to append b to a without creating a copy of a.

While JavaScript doesn't have a dedicated append function, there's a surprisingly efficient and concise way to do it:

a.push.apply(a, b);

That calls the push method via apply, which accepts a context argument (what the this value should be during the call) and any array-like object providing the arguments to give the call. Since push allows you to push multiple elements with a single call, that works a treat. And somewhat unusually for JavaScript, it's probably the most efficient way to do it on all platforms (where normally this sort of thing is faster on some and slower on others)

Now, if you do this in code other people are going to have to read, I'd recommend a comment saying "Appends `b` to `a` in place" or some such, because otherwise it's pretty opaque to people who don't know JavaScript well. Or, of course you could always add an append method to arrays:

(function() {
var push = Array.prototype.push;

function Array_append(array) {
push.apply(this, array);
return this;
}

if (Object.defineProperty) {
Object.defineProperty(Array.prototype, "append", {
enumerable: false,
value: Array_append
});
}
else {
Array.prototype.append = Array_append;
}
})();

As always, if you're doing that on platforms that don't have Object.defineProperty (and there are still a lot in the wild), make sure you don't have any broken for..in loops lying around.