Posts Tagged ‘Functions’

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

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

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.