Posts tagged with 'arrays'

JavaScript for C# developers: converting arguments into an array

Way back in March 2009, I wrote a quick post about the JavaScript arguments quasi-array, about how the interpreter sets it up on every call to every function to hold the arguments passed to that function.

Brown paper wrapped parcelAlthough I blithely talked about the fact that arguments was array-like, it wasn’t a real array (it’s not typeof Array) and didn’t have methods like pop() and the like. In fact, it only really has a length property and a bunch of properties named ‘0’, ‘1’, ‘2’ and so on. So it’s easy to iterate over the elements, er, properties, but that’s essentially it.

It’s actually quite easy to convert it to an array and then use that. You don’t even have to use the obvious for loop to do it either. You use the Array’s prototype’s slice() method:

var argsArray = Array.prototype.slice.call(arguments);

Since arguments does not have the slice() method, we have to use the call() function to call it on arguments (this is an application of the apply invocation). slice() returns part of an array as an array, but If you don’t pass any arguments to it – start index, end index – the function returns all of the elements instead. Which is, if you think about it, what we want.

So, if you have, say, a logging library for your code, and you want to log the values of the arguments to a particular function, you could do something like this:

var convertArgs = function (args) {
  return Array.prototype.slice.call(args);
};

var myLoggingLibrary = {
  logArguments: function (argsArray) {
    console.log(argsArray);
  } 
};

var someFunctionToTest = function (a, b, c, d) {
   // do something with the arguments; we’ll just print the first
   console.log(a);
};

var addArgumentsLogging = function (f) {
  return function () {
    var args = convertArgs(arguments);
    myLoggingLibrary.logArguments(args);
    f.apply(this, args);
  };
};

someFunctionToTest(1, 2, 3, false); // prints "1"

someFunctionToTest = addArgumentsLogging(someFunctionToTest);

someFunctionToTest(1, 2, 3, false); // prints "[1, 2, 3, false]" then "1"

With the addArgumentsLogging() function, I am not altering the function to be logged: I am merely creating a wrapper around it that does the logging and then calls the original function using the apply invocation. Notice how I’ve replaced the original function with the wrapped version. (Note also that the addArgumentsLogging function creates a closure over the parameter f.)

So there you go: how to convert the arguments quasi-array into a real array and then use it.

Album cover for Goodbye Country (Hello Nightclub)Now playing:
Groove Armada - Little By Little
(from Goodbye Country (Hello Nightclub))


PCPlus 293: Building an efficient dictionary

I think this is pretty much the last article I’ve written for PCPlus that discusses algorithms in a fairly formal sense. As I said last time, my editors and I have slowly been moving my articles towards more “how it works” topics than the traditional “layman’s guide to algorithms” subjects I’m perhaps better known for.

PC Plus logoThis one was essentially a discussion of big-Oh notation and how we can use it to categorize algorithms in terms of their overall performance and memory usage. To illustrate the notation, I used the abstract data structure known as an associative array, or dictionary, implementing it in several different ways, and showed each efficiency in terms of big-Oh. I not only discussed the average big-Oh values, but also the best-case and worst-case scenarios.

The implementations I used were unsorted arrays, sorted arrays (and binary search), hash tables, balanced binary search trees, and I briefly touched on radix trees and ternary trees.

Not too bad an introduction to big-Oh, if I say so myself.

This article first appeared in issue 293, April 2010.

You can read the PDF here.

(I write a monthly column for PCPlus, a computer news-views-n-reviews magazine in the UK (actually there are 13 issues a year — there's an Xmas issue as well — so it's a bit more than monthly). The column is called Theory Workshop and appears in the Make It section of the magazine. When I signed up, my editor and the magazine were gracious enough to allow me to reprint the articles here after say a year or so.)

Album cover for Gran RiservaNow playing:
dZihan & Kamien - Stiff Jazz
(from Gran Riserva)


A JavaScript tip that’s jarring: remove falsy elements from array

Elijah Manor tweeted a link today for learnjs, a reader-supported site that provides tutorial videos on writing JavaScript. A pretty good resource to have to be sure, but there was one video there that brought me up short.

The video describes how to filter falsy values (false, null, undefined, 0, NaN, the empty string) from an array. No problem with that but it uses the Boolean constructor in order to do it. Here’s the equivalent code from the video (and from another site I found that espouses this tip), so you don’t have to watch it:

var sourceArray = [false, true, null, { a: false }, undefined, 0, 42, NaN, "false", ""];
var filteredArray = sourceArray.filter(Boolean);
console.log(filteredArray); // prints [true, Object { a=false }, 42, "false"]

The first thing to point out is that the filter function is from JavaScript 1.6 or later (or ECMA-262 5th Edition), so is not present in all browsers. In particular it’s not available in IE8 or earlier (I haven’t downloaded IE9 yet). So this tip won’t work in what’s arguably the most popular browser on end-users’ machines. The Mozilla Dev Network (MDN) defines a function that  you can use to add a compatible Array.prototype.filter function to those browsers that don’t support it. It’s on the page that describes the filter function.

Now onto the thing that really gave me pause: the use of the Boolean constructor function as a normal function. One of the biggest hazards of using constructor functions is that there’s nothing in the language that enforces their use with the new keyword. You can in fact use them as normal functions with nary a warning from the interpreter. What happens when you do? Well, ignoring the built-in constructors (like Boolean, String, Date, etc, which are part of the interpreter’s run-time), unless the writer of the constructor went to great pains to cater for the case of calling the constructor as a normal function, the this variable inside the function will point to the global window object. You could be clobbering essential members of the global object. You could be adding global functions and variables. All bad things.

Hence the universal recommendation or convention that (1) constructors are named with an initial capital letter and normal functions with an initial lowercase letter, and (2) you never use constructors as normal functions. The convention is there to trigger a subconscious warning (since the interpreter won’t give you an actual one) as you use constructors: it’s got an initial uppercase letter so I must use new.

So, although the tip is cool (in the sense of using the minimal number of keystrokes to get something done), there’s no way I’ll be using it. It just looks wrong to me (what’s that constructor doing in there?). I’d use:

var filteredArray = sourceArray.filter(function (x) { return !!x; });

Although I’d admit that double-bang pattern is a little jarring the first time you see it (the right ! operator coerces the operand to a boolean value of the wrong sense, so the left one converts the result to the sense we want). However it’s not as jarring as using a constructor as a function.

Album cover for Piano WorksNow playing:
Armstrong, Craig - Weather Storm
(from Piano Works)


JavaScript for C# Programmers: Arrays

Another episode in the series where I talk about using JavaScript, but from a C# programmer's perspective.

This episode: arrays.

Couldn't be simpler, eh? A contiguous-in-memory set of elements all of the same type, random access by integer index (starting at zero, as decreed in the mists of time), the number of elements is fixed, bounds checking on the index, and so on. Oh, sorry, that was for C#, JavaScript is different. Yes, forget all that stuff you did know about arrays. Let's learn it all afresh.

Arrays look familiar

An array in JavaScript is an object, with some special methods that provide array-like behavior. Like C#, an array is declared with square brackets, but, unlike C#, the elements in an array can be anything you like:

var myArray = [
    true,
    42,
    NaN,
    Infinity,
    "some string",
    { name: "George", age: 42 },
    ["a", "string", "array"],
    null,
    undefined
];

Using this array, we can write code to read and write elements like this.

console.log(myArray[1]);         // outputs 42
console.log(typeof myArray[5]);  // outputs "object"
myArray[6] = 3.14159;            // replace nested array with number
console.log(myArray[6]);         // outputs 3.14159

Arrays are not fixed in length

One of the more important properties of an array is length:

console.log(myArray.length);  // outputs 9

It all seems fairly reasonable. However, check this out:

myArray[1000000] = "huh?";
console.log(myArray.length);  // outputs 1000001

The length of an array in JavaScript is not the number of elements in the array like we're used to in C#, but instead the index of the last element plus 1. It is almost acting like a sparse array: if you try and read myArray[42] that hasn't been set anywhere, for example, you will get undefined. Note in particular that this behavior means no array bounds checking, so beware.

So already the array is acting differently. But there's more: length is writeable. If you set length to something greater than it was, you are not allocating any more space: the new "logical" elements are all undefined if you try and read them. If you set length to some smaller value, any "actual" elements that are in between the old and new lengths are deleted.

Using this knowledge, adding a new element to the end of the array is simple:

var pi = [3, 1, 4, 1, 5];
pi[pi.length] = 9;
console.log(pi); // outputs [3, 1, 4, 1, 5, 9]

That is, you just set the element with index equal to the length. Or you can use the push method:

pi.push(2);
console.log(pi); // outputs [3, 1, 4, 1, 5, 9, 2]

With the same result (and, yes, there is a pop, which does what you expect).

Arrays really are objects

Before you go, well, duh, they are in C# too, I mean something much deeper than that. Remember that an object in JavaScript is a hash map with string keys (property names) and values that are whatever type you like? Well, an array is exactly the same. When you read the second element of your array, myArray[1], what's happening is that JavaScript will convert the index number to a string, "1", and use that as the key/property name to find the value. That's why arrays act like sparse arrays when you add a new element whose index is much larger than the previous one: it's merely adding a new property, a new key/value pair. (Ok, the interpreter does do some extra work to set the length property, but it's certainly not allocating a whole bunch of empty elements.)

Because an array is really an object hiding behind a special name, you can use for..in to enumerate the array elements:

var element;
for (element in pi) {
    console.log(pi[element]);
}

And it will enumerate the elements of the array. However, you should not use for..in with arrays: remember that a hash map (or dictionary) is not guaranteed to store elements in any kind of obvious order. After all the values are designed to be retrieved by key, and the hash map doesn't necessarily store items in key order. This is the main reason that for..in is not the equivalent of C#'s foreach. Instead, of course, you should use the usual for loop to enumerate the values in an array:

for (var i = 0; i < pi.length; i++) {
    console.log(pi[i]);
}

(Fun algorithmic aside: running the for..in loop above produces the elements in the correct order. I'm going to guess here that for small arrays and objects, elements are stored in sequence until some point when the whole object is large enough to be converted into a normal hash table. When hash maps are small a linear search will be faster than the whole "generate a hash code, index into the hash table, and avoid collisions if need be" algorithm. At some tipping point, it'll be faster to do the more complex version and so the container is recreated. If you recall, the .NET HybridDictionary class from System.Collections.Specialized uses this technique.)

Identifying array objects

The constructor function is Array. The typeof operator, applied to an array, returns the string value "object".

Yes, we have another weirdly thought out identification scheme. One way of working out whether a variable is an array or not is this:

var isArray = function(value) {
    return (value) &&
        typeof value === "object" &&
        value.constructor === Array;
};

The first clause in that expression is essentially checking to see if value is not null or undefined. Now that we have such a function, we can easily write other functions that can act of a single value or on an array of values.

Next time we'll look at the basics of functions. After that? Well, the world is our oyster.

Album cover for Songs 1993-1998 Now playing:
Moby - Anthem
(from Songs 1993-1998)


Search

About Me

I'm Julian M Bucknall, the M because it's my middle initial and because I and the other Julian Bucknall (the movie guy) would like to differentiate ourselves.

I'm a programmer by trade, an actor by ambition, and an algorithms guy by osmosis. I write articles for PCPlus in my spare time, not that there's much of that.

Julian M Bucknall Apart from that, an ex-pat Brit, atheist, microbrew enthusiast, Pet Shop Boys fanboy, slide rule and HP calculator collector, amateur photographer, Altoids muncher.

DevExpress

I'm Chief Technology Officer at Developer Express, a software company that writes some great controls and tools for .NET and Delphi. I'm responsible for the technology oversight and vision of the company.

Validation

Validate markup as HTML5 (beta)     Validate CSS

Bottom swirl

Archives

February 2012 (4)
SMTWTFS
« Jan  
1234
567891011
12131415161718
19202122232425
26272829

Like this Archive Calendar widget? Download it here.

Social networking

Google ads

The OUT Campaign

The OUT Campaign

My Tweets

Bottom swirl