Using Properties and Tuples to Get Multiple Values from a JavaScript Function

Here’s a word: expando. Here’s a sentence using the word: JavaScript has expando objects.

Expando sounds like a silly made-up word. And it might be. But it’s also an actual word in Latin. It means ‘to spread out.’ The Latin meaning is almost appropriate for JavaScript. Objects in JavaScript are expando objects because properties can be dynamically added (expanding the object) and removed.

var obj = new Object();

// add a property
obj.foo = 'bar';

// remove a property
delete obj.foo;

Since functions in JavaScript are first class objects, properties can be added to functions. A function can be made state-ful by setting a property. In the example below a function named process sets an error property on itself:

function process(input)
{
    process.error = 0;
    ...
    if (...)
    {
        process.error = 1;
    }

    return output;
}

If the process function has never been run, process.error will be undefined.

if (typeof(process.error) != 'undefined')
{
    // test for an error
    ...

In newer versions of JavaScript this test could be written more directly as (process.error != undefined) but using the typeof operator is more portable.

The undefined state could be eliminated by initializing the property outside the function:

var process = function(input) { ... };
process.error = 0;

Are state-ful functions a good practice? It would be problematic if the function can be called again before the previous state has been handled so, in general, keeping state in a function should probably be avoided.

Yes, I just said don’t do the thing I just showed how to do.

Instead of creating state within the function, the function can return a tuple. (Like expando, tuple has a Latin etymology. Did you think you would be learning so much Latin from a blog post on JavaScript?) Tuple is a term used in set theory and by extension the relational database model but in terms of functional programming a tuple is an object that holds several other objects.

A tuple could be implemented as an Array. Using an array would require knowing the position in the array of each specific datum. Depending on positional information is brittle especially for large sets. A better way is an implementation that supports named datums. With named datums the order is irrelevant and the code is more literate.

Here’s the process function modified to use an ad-hoc tuple:

function process(input)
{
    var tuple = new Object();
    tuple.output = null;
    tuple.error = 0;
    ...
    if (...)
    {
        tuple.error = 1;
    }

    return tuple;
}

Using the object literal syntax the tuple object and its properties can be created in one line instead of three:

    var tuple = {output: null, error: 0};

Finally the returned tuple result could be handled as follows:

var result = process(in);
if (result.error == 0)
{
    // do something with result.output
    ...
}

Related Posts:
JavaScript Closures

JavaScript Closures

JavaScript doesn’t get enough respect. Sure it has warts but it also has elegant features like closures.

What, you may be asking, is a closure?

Many programming languages make a sharp distinction between code and data. JavaScript does not. In JavaScript a Function is a ‘first class’ type just like a String or an Array. Functions can be assigned to variables and properties and returned from other functions.

Declaring a function in JavaScript creates a function object. The following statement creates an object named example whose type, as reported by the typeof operator, is ‘function’.

function example(arg)
{
    return "example: " + arg;
}

The example function could also be created by a function literal1:

var example = function(arg) { return "example: " + arg; };

What gives rise to closures is the way the scope chain is handled when a function is created.

Consider:

var test0;
function outer()
{
    var test1;
 
    function inner()
    {
        var test2;
    }
}

JavaScript is a lexically scoped language. In the code above test0 is a global variable and test1 is local to the outer function. outer gets a reference to the global scope and test0 and test1 are both within scope for outer. test2 is local to the inner function. A function, in this case inner, always gets a reference to the scope chain in effect at the place where the function is defined. That is, inner gets a reference to outer’s local scope which in turn chains to the global scope. test0, test1, and test2 are all in scope for inner.

If the preceding description of scope makes sense, then consider this code:

function makeFish(color)
{
    function fish()
    {
        return color + " fish";
    }
 
    return fish;
}
 
var fish0 = makeFish('red');
var fish1 = makeFish('blue');
 
var str = fish0() + '; ' + fish1();

The variable str will be assigned the value “red fish; blue fish”. Why? Because the scope chain persists with the function object. The function is said to be ‘closed’ over the scope in which it was defined.

This isn’t just a neat parlor trick. Closures, along with first class functions and recursion, are generally considered the essentials for a style of programming known as functional programming.

Effective JavaScript Closures

Defining a function in JavaScript always creates a closure. Closure creation can not be disabled or turned off.

If the function is in the global scope then only the global scope is captured in the closure. In general that’s not useful so it’s often ignored as a case of a closure. But be aware that implicitly defined variables, that is variables defined without a var statement, are always in the global scope.

JavaScript is not block scoped. C/C++, Java, and C# are all C style syntax languages and all are block scoped languages. JavaScript has a C style syntax but it is not block scoped.

It’s a common technique to leverage block scope to control the lifetime of variables. In JavaScript, variables are in scope throughout the function they are declared in, not just the block they are within. In function foo below the idx variable exists before and after the for statement’s block. In JavaScript a variable can’t be forced out of scope prior to exitting its function.

function foo()
{
    var str = '';
    for (var idx = 0; idx < 5; ++idx)
    {
        str += idx;
    }
    return str;
}

Closure Conniptions

You may have heard that JavaScript closures are evil and cause memory leaks. Nonsense. Closures are not evil.

Oh. The memory leak thing? Well, yeah. There’s an Internet Explorer memory leak issue2 that closures often get the brunt of the blame for. That’s unfortunate because the memory leak issue is not really a closure problem. It’s a host object integration issue.

JavaScript supports native objects and host objects. Native objects are the built-ins (e.g. Object, Function, Array, String, Number) and user defined objects. Host objects are provided by the hosting application.

For an example take the window object. The window object is not part of the JavaScript language. Yes I know your JavaScript book spends chapters on the window object. That’s because most JavaScript programmers are writing to web browsers and every web browser has a window object. But although every web browser provides a window object not every JavaScript host is a web browser.

With closures it can be very easy to create circular references between objects. (That’s bad.) But JavaScript’s garbage collector is capable of detecting and handling circular references. (That’s good.) Except that, in IE, COM based host objects aren’t managed by the JavaScript garbage collector. (That’s bad.) DOM objects in IE are COM host objects. (That’s more bad.)

The fix is easy. Don’t depend on the garbage collector. Clean up after yourself. Release and null out object references when you’re done with them.

Link: Scott's "SiteExperts" Place: Closures and IE Circular References.
Link: Fabulous Adventures In Coding : What are closures?.

Related Posts:
Using Properties and Tuples to Get Multiple Values from a JavaScript Function

1 In addition to function statements and function literals, a function can also be created by the Function constructor.

var example = new Function("arg", 'return "example: " + arg;');

The Function constructor behaves differently from statements and literals with respect to scope. It always creates the function in the global scope. That difference makes the function constructor generally non-useful for closures.

2 I would assume that the other JScript script engine hosts, WSH and ‘classic’ ASP, have the same issue.

Block Comment Quick Trick

Sometimes it’s useful to be able to quickly add or remove a section of code. Some languages have preprocessors that can help but here’s a ‘stupid’ comment trick to achieve the same.

C-style syntax languages (e.g. C, C++, Java, JavaScript, C#) support single line comments with ‘//’ and block comments with a ‘/*’ and ‘*/’ pair. The trick is that single line comments can be used to comment out block comments.

So here’s a commented out code block:

/*

    var lorem = 'ipsum';

    ...

//*/

Note the ‘//’ for a single line comment in front of the block comment terminator. The block can be uncommented with a single keystroke, by adding a ‘/’ before the block start.

//*

    var lorem = 'ipsum';

    ...

//*/

Problem with the Script Element for ASP Server-Side Object-Oriented JavaScript

‘Classic’ ASP (Active Server Pages) is a very quirky environment. A case in point is the handling of server side script elements.

For an ASP project I wanted to use object-oriented JavaScript (AKA JScript) on the server and I wanted to be able to reuse the JavaScript code across multiple pages. I didn’t expect to be pushing any boundaries but I quickly found myself in deep weeds.

Two parts of what I wanted to do could be considered unusual.

First, I wanted to use JavaScript on the server.

Microsoft encouraged the use of VBScript for ASP but I prefer JavaScript’s C style syntax, I think JScript’s exception handling has advantages over VBScript’s “on error”, and I like being able to use essentially the same language on both the client and the server.

Second, I wanted to write object-oriented JavaScript.

The JavaScript language is fundamentally object based yet, incongruously, object-oriented programming in JavaScript is often considered to be esoteric.

ASP server side code can be placed either within ‘<%’ and ‘%>’ delimiters (which is called a ‘scriplet’ in other environments) or within a script element with a non-standard runat="server" attribute.

In ASP reusing code across multiple pages means including shared files and in ASP 3.0 there are two ways to include a file: use a server side include directive* or a script element with a src attribute.

Link: Microsoft documentation on “Including Files in ASP Applications”

An example server side include directive:
<!-- #include file="server/include.inc" -->

The server side include directive performs a textual include of the referenced file. The included file can contain a mix of HTML and ASP scriptlets.

Since I wanted to just pull in code only, my include file would be one large scriplet.

But scriplets aren’t supported in the global.asa file. One of my goals was to avoid code duplication so I needed a way to include code without using a scriplet.

Here’s an example of a script element that includes a file server side:
<script language="javascript" runat="server" src="server/include.js"></script>

The included file can only contain code in the specified language. There’s no scriplet. That’s good.

However using script elements created a new set of issues.

In violation of the principle of least astonishment, ASP does not execute server side script in the order of its appearance within the page. The documented order of execution is:

  1. Script elements for non-default languages.
  2. Scriptlets (i.e. <% %> blocks).
  3. Script elements for the default language.

My default language was JavaScript. I would have a non-default language only if I were mixing languages, which I wasn’t.

This order of execution isn’t the whole story. Script elements for the default language appear to always be executed after the end of the page with the exception of function definitions. There’s apparently some auto-magical fix-up being performed so that functions defined in script elements can be called from scriplets.

In his blog, Fabulous Adventures in Coding, Eric Lippert wrote:

Ideally you want the server side <SCRIPT> blocks to contain only global function definitions, and the <% %> blocks to contain only “inline” code.

Link: Fabulous Adventures in Coding: VBScript and JScript Don’t Mix, at least in ASP

The apparent function definition fix-up seems to be half-baked.

In JavaScript functions are actually objects. A function named test could be equivalently defined either as:
function test() { return "test"; }

or as:
var test = function() { return "test"; }

Except in ASP the former definition would be available to scriplets and the latter definition wouldn’t be executed until the end of the page.

A bigger problem is that the order of execution has the unfortunate effect of blowing out prototype assignments.

An example will illustrate. Assume two files: circle.js and default.asp.

circle.js defines a constructor for a Circle type and assigns some additional properties to the Circle prototype. (The Circle type is borrowed from an example in the Microsoft JScript documentation.)

default.asp includes circle.js, creates an instance of a Circle, and iterates all of the members of the Circle object.

circle.js:

// circle.js

function Circle (xPoint, yPoint, radius)
{
    this.x = xPoint; // The x component of the center of the circle.
    this.y = yPoint; // The y component of the center of the circle.
    this.r = radius; // The radius of the circle.
}
Circle.prototype.pi = Math.PI;
Circle.prototype.area = function ()
    {
        return this.pi * this.r * this.r;
    }

default.asp:

<%@ language="jscript" %>
<script language="javascript" runat="server" src="server/circle.js"></script>
<html>
<head></head>
<body>
<%
var aCircle = new Circle(5, 11, 99);
    
// iterate the members/properties of the Circle object
for (var x in aCircle)
{
    Response.Write(x + " = " + aCircle[x] + "<br>");
}
%>
</body>
</html>

The output that might normally be expected:

area = function () { return this.pi * this.r * this.r; }
pi = 3.141592653589793
x = 5
y = 11
r = 99

The output that this page will actually produce:

x = 5
y = 11
r = 99

Why? Because the prototype assignments that add the pi and area members don’t execute until after the closing </html> tag.

Being able to set the prototype property is important because the prototype is an essential part of JavaScript’s support for object inheritance.

At this point some might settle for living with the evil of code duplication. That might be viable if the global.asa does little or nothing. My global.asa wasn’t going to be simple enough for that solution.

I needed a work-around. What I came up with was to create factory functions that wrapped the constructor definitions and the prototype assignments in a function scope.

Here’s a revised circle.js:

// circle.js

function createCircle(xPoint, yPoint, radius) // Circle factory
{
    function Circle (xPoint, yPoint, radius)
    {
        this.x = xPoint;
        this.y = yPoint;
        this.r = radius;
    }
    Circle.prototype.pi = Math.PI;
    Circle.prototype.area = function ()
        {
            return this.pi * this.r * this.r;
        }
    
    return new Circle(xPoint, yPoint, radius);
}

Constructing a Circle now looks like:
var aCircle = createCircle(5, 11, 99);

If there is an inheritance chain, all of the objects could be defined within the scope of the factory function and the factory function could take a selector argument to determine which type of object to construct.

The function scope trick is not a perfect solution. One issue is that a type defined within a function scope can’t be used with the instanceof operator. But the function scope trick does give me a way to get most of the benefit of leveraging JavaScript’s object oriented capabilities despite ASP’s best efforts to confound.

* The server side include directive is often confused with real SSI. It’s not SSI. It’s ASP aping the syntax of SSI. It’s a curious choice because ASP otherwise follows a very different syntax model. Another curiosity is that the documentation states “ASP includes files before executing script commands” and then belies that statement with an example of including a file multiple times by using a server side include directive within a for loop.

Cross-Language Gotcha: split() with a Limit

I have always assumed that the split() and join() methods of JavaScript’s String and Array objects were inspired by Perl. It’s a striking resemblance if my assumption is wrong.

Briefly the split() function splits a string on a delimiter producing an array of substrings. join() is a complementary function. join() operates on an array and produces a string by concatenating all the elements of the array with the specified delimiter.

In Perl, split() looks something like:
      split separator, stringExpr, limit

And in JavaScript:
      stringObj.split(separator, limit)

In both languages separator can be a literal string or a regular expression. Languages vary in their support of regular expressions so it’s no surprise that Perl and JavaScript interpret certain separators differently.

The gothca that tripped me up is that JavaScript and Perl don’t agree on what limit means. In both languages limit is optional but when specified split() will produce an array with only limit number of elements.

This Perl code:

my $str = "apple:boat:cat";
my @vec = split(':', $str, 2);

will produce an array with the elements “apple” and “boat:cat”.

This JavaScript code:

var str = "apple:boat:cat";
var vec = str.split(':', 2);

will produce an array with the elements “apple” and “boat”.

Conceptually JavaScript splits the whole string but only returns the first limit number of substrings while Perl returns the first limit - 1 substrings and the ‘unsplit’ balance of the string.

The JavaScript behavior can be imitated in Perl something like this:

my $str = "apple:boat:cat";
my @vec;
($vec[0], $vec[1]) = split(':', $str);

There is no equivalent for the Perl behavior in JavaScript.