Archive for the ‘Functions’ 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?

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!"

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

Returning functions

Tuesday, September 15th, 2009

Functions are objects, so they can be passed around like callbacks for example and also returned by other functions.

You call a function that does some complicated setup and as a results returns a new function. You assign the result to a new function and use it afterwards.

function setup() {
    alert(1);
    return function() {
        alert(2);
    };
}
var my = setup(); // alerts 1
my(); // alerts 2

Your setup function can store some private data in a closure and use that data somehow.

Here setup() creates a counter function, which gives a next ID for example. But the count variable is not exposed.

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

Callbacks

Tuesday, September 15th, 2009

Since functions are objects they can be passed as arguments to other functions.

function test(a, b, fn) {
    fn(a, b);
}

In this simple example we have a function test() that takes a function fn as a third parameter and calls that function passing the first two parameters.

When you cal the test() function, you can pass a pointer to an existing function myFunc() or you can also pass an anonymous function.

test(1, 2, myFunc);
 
test(1, 2, function(one, two){
    console.log(arguments);
});

Examples

For examples of this pattern in the wild Ė well, every time you attach an event listener, you pass a callback function.

document.addEventListener(
    'click', 
    animateAndWowUser, 
    false
);

Same with timeouts and intervals. setTimeout() and setInterval() expect a function and call it back after the specified number of milliseconds.

var thePlotThickens = function(){
  console.log('500ms later...');
};
setTimeout(thePlotThickens, 500);

And here's a common anti-pattern Ė passing a string where a function is expected. The JavaScript engine has no choice but to evaluate the string (like with eval()) and execute it, which is unnecessary work.

// anti-pattern
setTimeout("thePlotThickens()", 500);

Self-executing functions

Tuesday, September 15th, 2009

Update: "Immediate functions" sounds like a much better name.

Self-executable functions are simple and powerful.

All you do is add a set of parentheses after the function and this causes it to be executed right there. If itís an anonymous function you also need to wrap it in parentheses.

(function(){
   var a = 1;
   var b = 2;
   alert(a + b);
})();

You can also pass parameters to the self-executing function if you want.

(function(a, b){
  var c = a + b;
  alert(c);
})(1, 2);

So how is this pattern useful?

Itís useful when you have some work to do, some initialization maybe. You need to do it only once and you donít want to leave any globals lying around after the work is finished. All the temporary variables you need like c in the case above remain local and don't pollute the namespace.

Useful also when your code is kind of a guest to the page. Like a bookmarklet for example, or a widget of some sorts. You donít want to add your variables and functions to the host pageís naming space and possibly causing a naming conflict with the page's core code.

Functions are objects

Tuesday, September 15th, 2009

Functions are objects, itís very important to keep that in mind.

Functions are objects so they can have properties. And they they have methods.

They can be copied, deleted, passed as arguments to other functions, returned by other functions.

They also provide scope.

And they have special feature that sets them apart from the other objects Ė they are invokable, they can be called.

Init-time branching

Monday, September 14th, 2009

Probably virtually every web developer has done something like this at one point or another:

function myEvent(el, type, fn) {
  if (window.addEventListener) {
    el.addEventListener(type, fn, false);
  } else if (window.attachEvent) {
    el.attachEvent("on" + type, fn);
  }
}

This is absolutely normal, browsers are different, we have to take this fact into account and branch our code. One way to improve similar bits of code is by branching only once, when the function/method is defined as opposed to every time it's called. Like this:

if (window.addEventListener) {
  var myEvent = function (el, type, fn) {
    el.addEventListener(type, fn, false);
  }
} else if (window.attachEvent) {
  var myEvent = function (el, type, fn) {
    el.attachEvent("on" + type, fn);
  }
}

This way you get browser-dependent myEvent() function and there's no branching every time the function is called. While this may sound unnecessary, it could have an impact when a function is called many times in performance-critical situations, such as during drag-n-drop.

In a drag-drop case, it's likely that you need to get the current (computed) style of an element and also set it. Getting the computed style is different in browsers and is an ideal candidate for load-time branching. This is how it's done in the YUI DOM utility (source code), where this pattern was actually isolated from.

The DOM utility does more stuff, but the purpose of simply demonstrating the pattern you can say that it does something like:

// load-time branching
if (document.defaultView && document.defaultView.getComputedStyle) {
  var getStyle = function(el, property) {
    return document.defaultView.getComputedStyle(el, '')[property];
  }
} else if (document.documentElement.currentStyle) {
  var getStyle = function(el, property) {
    return el.currentStyle[property];
  }
}
 
// usage
var style = getStyle($('something'), 'fontWeight');

Another benefit of load-time branching is that you can branch only once and define multiple functions. For example if you've detected that the browser supports window.addEventListener it's very likely that it will support window.removeEventListener as well and not window.removeEvent. This should be approached carefully though, so that you keep in mind to branch based on object/feature detection and not on browser detection. For example don't be tempted to define getStyle() based on detection for window.addEventListener, although it will most likely work.