Archive for the ‘Patterns’ Category

Optional parameters

Monday, February 11th, 2013

JavaScript has no syntax that allows you to have a default value for a function parameter as you often do in most other languages. This is scheduled for a future version of ECMAScript, but for now you have to take care of this yourself inside the body of your function.

There are several patterns that do the job, but here's a new one. It was suggested to me by Andrea "WebReflection" Giammarchi in his technical review of the upcoming JS4PHP book.

Andrea doesn't remember blogging about this pattern and I don't remember ever seeing it. So here goes.

Say you have a function with all 4 default parameters, mimicking for example PHP's declaration:
function sum($a = 1, $b = 2, $c = 3, $d = 4) ...

function sum(a, b, c, d) {
  // note no `break` needed
  switch (arguments.length) {
    case 0: a = 1;
    case 1: b = 2;
    case 2: c = 3;
    case 3: d = 4;
  }
  return a + b + c + d;
}

Test:

sum();            // 10
sum(1);           // 10
sum(11);          // 20
sum(1, 2, 3, 24); // 30
sum(11, 22);      // 40

Obviously this doesn't work when you have an optional param, followed by a required one, but that's just bad design.

Thoughts?

Shim sniffing

Monday, June 4th, 2012

Extending native objects and prototypes is bad. If not vile, mean and Jesuitic.

// Noooooo!
Array.prototype.map = function() {
  // stuff
};

Unless it's desirable, for example for adding ECMAScript5 methods in legacy browsers.

In which case we do something like:

if (!Array.prototype.map) {
  Array.prototype.map = function() {
    // stuff
  };
}

If we're paranoid enough we can even try to protect from somebody defining map as something unexpected like true or "the peaches are this way":

if (typeof Array.prototype.map !== "function") {
  Array.prototype.map = function() {
    // stuff
  };
}

(Although that ultimately breaks the other developer's map to the peach trees)

But in a hostile dog-eat-dog cut-throat environment (in other words when you provide or consume a library), you trust no one. What if that other smartass JS loads before your badass JS and defines map() in a way that is not really ES5-compliant and your code doesn't work anymore?

You can always trust browsers though. If Webkit implements map() you can relax that it should probably work OK. Otherwise you'd want to go ahead with your shim.

Luckily that's easy to do in JavaScript. When you call toString() of a native function it should return a string with a function that has a body of [native code]

So for example in Chrome's console:

> Array.prototype.map.toString();
"function map() { [native code] }"

A proper check is ever-so-slightly painful because browsers seem to be a little frivolous with white spaces and new lines. Testing:

Array.prototype.map.toString().replace(/\s/g, '*');
// "*function*map()*{*****[native*code]*}*"  // IE
// "function*map()*{*****[native*code]*}" // FF
// "function*map()*{*[native*code]*}" // Chrome

Simply stripping all \s will give you something more workable:

Array.prototype.map.toString().replace(/\s/g, '');
// "functionmap(){[nativecode]}"

You can opt in for a reusable shim() function so you don't have to repeat all that !Array.prototype... jazz. It can take an object to augment (e.g. Array.prototype), a property to add (e.g. 'map') and a function that implements the shim.

function shim(o, prop, fn) {
  var nbody = "function" + prop + "(){[nativecode]}";
  if (o.hasOwnProperty(prop) &&
      o[prop].toString().replace(/\s/g, '') === nbody) {
    // native!
    return true;
  }
  // shim
  o[prop] = fn;
}

Testing:

// this is native, cool
shim(
  Array.prototype, 'map',
  function(){/*...*/}
); // true
 
//  this is new
shim(
  Array.prototype, 'mapzer',
  function(){alert(this)}
);
 
[1,2,3].mapzer(); // alerts 1,2,3

p.s. And then
there's JJD's! (backstory)

The ridiculous case of adding a script element

Saturday, September 10th, 2011

Adding a script element to a page should be a no-brainer. Yet, it's ridiculously unreliable in the wild - when you don't have any idea of the surrounding markup.

You know the drill - create a script element, point its src to a URL and add it to the page so that script file can be downloaded in a non-blocking manner.

Creating the script is nice and easy:

var js = document.createElement('script');
js.src = 'myscript.js';

The problem is how to add it to the page.

1. to the head

Probably the most common approach is to append to the head of the document:

document.getElementsByTagName('head')[0].appendChild(js);

You get all head elements (there should be only one) and you add the script there so the result is

<html>
  <head>
    <script>
    ...

But what if there's no head in the document? Remember, we want solid robust code that always works.

Well turns out that most browsers will create the head element even if the tag is not there.

Most, but not all as Steve Souders' browserscope test shows. Exceptions include browsers like Opera 8 but also Android 1.6 and one iPhone 3 - hardly old and negligible.

So head is out.

2. add to the body

This is even shorter:

document.body.appendChild(js);

what if there's no <body> tag? Well my test shows that all tested browsers will create a body element. Even one that has a working appendChild() method. Now, while some of those that don't create head, do create body, I'm still a little uncomfortable that I couldn't find a single browser that doesn't create body. Makes me feel a little worried about the testing and data collecting.

But even if we assume that in all browsers, document.body always exist, there's still a problem. IE7 and the dreaded "Operation aborted" error.

If you modify BODY while loading the page and from a script that is not a direct child of body, but nested in another element, you get Operation aborted and nothing works.

Surprisingly simple page fails miserably:

<html>
  <body>
      <div>
          <script>
          var js = document.createElement('script'); 
          js.async = true;
          js.src = "http://tools.w3clubs.com/pagr/1.sleep-2.js";
          document.body.appendChild(js);
          </script>
      </div>
  </body>
</html>

See it live in IE7 and be amazed

Now operation aborted may be solved with a defer, but maybe not in IE9.

Another reason not to attempt anything with body is if the script is included in the head. At execution time we have not reached <body> yet, so document.body doesn't exist. Demo.

3. use documentElement

document.documentElement is the html doc itself. Now that's got to exist no matter what.

So you go like

var html = document.documentElement;
html.insertBefore(js, html.firstChild);

And it works!

But what if the firstChild is a comment before the head? This makes something kinda weird:

 
<html>
  <script>
  <!-- comment -->
  <head>
    ..

Script obviously has no place there, but my test page worked in ie6789, and recent versions of FF, Chrome, Safari, Opera.

But looks like there are other browsers where this comment thing fails as reported(btw, good to read the whole post and all the comments) by Google Analytics folks who say they have received complaints when they used to do that. There might be other cases or browsers I didn't try. So reluctantly, we move on.

4. hook to the first script

Ahaa, if you're running a script, then this script must either be inline <script>bla</script> or external <script src="meh.js">. Either way, there's gotta be at least one script tag! Wo-hoo!

So the final solution is:

var first = document.getElementsByTagName('script')[0];
first.parentNode.insertBefore(js, first);

No matter where the first script might be, we glue out new one right above it.

Drawback is that looking for script nodes might be a little more expensive than looking for document.documentElement or document.body or the single match of getElemenetsByTagName('head')

There's still a case when there might not be a script element at all. Ah, impossible, since we're running a script there must be a script element! Well (and thanks to @kangax who pointed this to me while he was reviewing JavaScript Patterns!) here's one example:

<body onload="alert('Look ma, executing script without a script tag!')">

Overall while not completely foolproof, this is as close as you can get to being able to achieve the simple task - add a new script node. Isn't web development just magnificent?

(Funny thing if you use this only to load a script asynchronously: in order to load a script (file), you need a script that refers to a script, possibly itself. JavaScript all around.)

Once again the whole snippet:

var js = document.createElement('script');
js.src = 'myscript.js';
var first = document.getElementsByTagName('script')[0];
first.parentNode.insertBefore(js, first);

JavaScript classes

Thursday, May 5th, 2011

OK, think of it as a religious flamewar to the likes of "tabs vs. spaces for indentation". Looks like this particular war is currently (at JSConf and NodeConf) even more heated than it should be. Classes vs prototypes. For or against classes.

I personally don't care about the "winner". The thing is that classes currently don't exist in JavaScript. No such thing. However looks like they might in the next iterations of the language (see latest post from Brendan Eich). Some people miss classes so much that they start calling other things classes or come up with some approximation. Problem is, because classes don't exist, people often mean different things when they say "class".

Sometimes they mean "constructor functions". Sometimes they mean a regular object literal (singleton-type thing. Heck, "singleton" is also open for interpretations). Sometimes they mean an object or a function defined using Crockford's module pattern.

Sometimes it's some completely different home-grown (or library-provided) thingie called klass for example (in my "JavaScript Patterns" book I have one example for educational/thought-provoking purposes). It has to be klass, or _class or something weird. Because class is a reserved word. Unused, but reserved. And one day may be full of meaning. See the problem?

I avoid saying "class". It just doesn't exist. Imagine two months down the road ECMAScript comes up with classes. And they will most certainly not be the classes you may mean today (e.g. classes won't be another name for constructor functions, I'm sure).

So any written text/blog/documentation you've produced will become incorrect and even worse - misleading and confusing.

To summarize:

  • saying "class" today is confusing and takes extra effort to process (what do you mean? what was that again? it doesn't really exist and is not defined in the language, so an extra translation step is required)
  • saying "class" today will read plain wrong tomorrow, will confuse and misinform

Note:
Heck, even I have this "how to define a JavaScript class" post on my other blog. I wrote it years ago when, coming from PHP, I was curious how stuff works in JavaScript. Well I got it wrong then. But fixed it not too long ago because it was top 1 result in google and Yahoo search for "javascript class" and "javascript classes" and I didn't want to continue contributing to the confusion.

Note 2:
To my regret, I couldn't make it to JSConf (aka the best!) nor NodeConf this year (because all girls and women in my life are born in May and it's impossible to travel) so I may be a little off on the level of flamewarfare, but according to Twitter I'm not.

Singleton without a closure

Saturday, July 17th, 2010

Warning: anti-pattern ahead.

Mwahaha, I feel like a ninja. I mean a ninja by Doug Crockford's definition which means someone who finds a mistake in the language's design, decides it's cool and abuses it.

So there you go. Regular expression objects are created only once if you're using a literal. Such an object can be used to store the single instance of a Singleton() constructor.

Implementation

function Single() {
    "strict me not!";
 
    var re = / /;
    if (re.instance) {
        return re.instance;
    }
    re.instance = this;
    this.name = "Foo";
 
}
 
Single.prototype.getName = function () {
    return this.name;
};

Test

var s1 = new Single(),
    s2 = new Single();
 
console.log(s1 === s2); // true
console.log(s1.getName()); // "Foo"
s1.name = "dude";
console.log(s2.getName()); // "dude"

Pros

  • The prototype chain works fine
  • No closures
  • No public properties or globals to store the single instance

Cons

  • It's a hack
  • ES5 defines that reg exp literals should no longer work like this

Verdict

Don't use. Please :)

Constants

Saturday, April 10th, 2010

Although there actually are constants in some environments, e.g. in Firefox you can use const instead of var, in general in JavaScript there are no constants.

Workaround

To work around that limitation, people often use ALLCAPPS to denote "hey, don't touch this var, it's meant to be a constant". It's constant-by-convention but the values can be changed by careless programmer on a bad day. If you really want to protect the value, you need to make it private.

PHP-inspired API

In PHP there are the functions define(name, value) to gefine a constant, defined(name) to check if a constant is defined and constant(name) to get the value of a constants when it's name is assembled at runtime and you don't know it a priori. So I thought - well, we can do the same in JavaScript. Only, let's not use global functions, but a constant global var and make the functions method of that global. constant.constant(name) is a little mouthful, so let's make that one constant.get(name)

Implementation

Here's the simple implementation:

"use strict";
 
var constant = (function () {
    var constants = {},
        ownProp = Object.prototype.hasOwnProperty,
        allowed = {
            string: 1,
            number: 1,
            boolean: 1
        };
    return {
        define: function (name, value) {
            if (this.defined(name)) {
                return false;
            }
            if (!ownProp.call(allowed, typeof value)) {
                return false;
            }
            constants[name] = value;
            return true;
        },
        defined: function (name) {
            return ownProp.call(constants, name);
        },
        get: function (name) {
            if (this.defined(name)) {
                return constants[name];
            }
            return null;
        }
    };
}());

This is it. Basically protect an object in a closure and don't provide means to change it, but only to add properties to it.

UPDATE: thanks to the comments (see below), there's extra care to check for own properties of the constants private object. This allows to define constants with weird names such as toString and hasOwnProperty. Also only primitive values are allowed to be constants.

Usage

// check if defined
constant.defined("bazinga"); // false
 
// define
constant.define("bazinga", "Bazinga!"); // true
 
// check again
constant.defined("bazinga"); // true
 
// attempt to redefine
constant.define("bazinga", "Bazinga2"); // false
 
// was it constant or it changed?
// get da, get da, get da value
constant.get("bazinga"); // "Bazinga!"

arguments considered harmful

Tuesday, February 16th, 2010

Inside every JavaScript function an arguments object is available containing all the parameters passed to the function.

function aha(a, b) {
  console.log(arguments[0] === a); // true
  console.log(arguments[1] === b); // true
}
 
aha(1, 2);

However, it's not a good idea to use arguments for the reasons of :

  • performance
  • security

The arguments object is not automatically created every time the function is called, the JavaScript engine will only create it on-demand, if it's used. And that creation is not free in terms of performance. The difference between using arguments vs. not using it could be anywhere between 1.5 times to 4 times slower, depending on the browser (more info and bench)

As for the security, there is the POLA (Principle of Least Authority) which is violated when one function A passes arguments to another B. Then a number of bad things can happen including:

  • B calls A through arguments.callee - something A never intended when calling B in the first place
  • B overwrites some arguments and causes A to misbehave

While in these scenarios B looks a little malicious, it can actually cause trouble unvoluntarilly. Consider this example that illustrates the second case (B changing values behind A's unsuspecting back)

function A(obj, ar) {
 
  console.log(obj); // {p: 1}
  console.log(ar);  // [1, 2, 3]
 
  B(arguments);
 
  // oops!
  console.log(obj); // {p: 2}
  console.log(ar);  // [1, 2]
}
 
function B(args) {
 
  // convenient innocent-looking local vars
  var o=args[0],
      a=args[1];
 
  // do something with the local variables
  o.p = 2;
  a.pop();
 
  // now the original arguments is 
  // messed up because objects/arrays
  // are passed by reference
}
 
A({p: 1}, [1, 2, 3]);

ECMAScript 5

In ECMAScript's "strict mode", using arguments.callee will throw a syntax error.

Recursive anonymous function

Probably the biggest argument for keeping arguments and arguments.callee is so that recursive anonymous functions can be created, because by using the callee property a function can call itself without knowing its own name. Now, this is not such a common scenario, but even if so, you can wrap a named function inside of an anonymous function and voila! - call that named function recursively without leaking a variable to the global scope.

Function properties

Tuesday, September 15th, 2009

Since functions are objects, and objects are mutable in JavaScript, you can add properties to your functions.

Why? For caching results of computations for example. Here's a memoization done this way.

function myFunc(param){
    if (!myFunc.cache) {
        myFunc.cache = {};
    }
    if (!myFunc.cache[param]) {
        var result = {}; // ...
        myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
}

Here myFunc() gets a cache property which is an object. The function does the complicated computations based on a parameter and ends up with a result object. Using the parameter as a key in the cache object, it stores the result.

Consecutive calls with the same parameter will get the result from the cache, no need to compute the same result again.

Lazy definition function

Tuesday, September 15th, 2009

This has a nice name – a lazy function definition. A lazy function is one that pretends to work but it doesn't really.

It does some work initially and then caches the result. Then on consecutive calls it only returns the pre-computed result, it doesn’t really do anything.

In order to do so, the function redefines itself with a new implementation, one that simply points to the computed result.

function lazy() {
    var result = 2 + 2;
    lazy = function() {
        return result;
    };
    return lazy();
}
 
lazy(); // 4
lazy(); // 4

Self-overwriting functions

Tuesday, September 15th, 2009

Next pattern – a function that overwrites itself, a self-redefining function. Pretty similar to functions that return functions, but this time the function is re-implemented from the inside, not returned.

function next() {
    var count = 1;
    next = function() {
        return ++count;
    };
    return count;
}
 
next(); // 1
next(); // 2