9007199254740992

After my discussion of JavaScript’s numeric limitations when working with integers, I was curious. There must be some integer that’s the biggest one that JavaScript can represent.

A brute force method (my favorite kind) would simply increment a variable and see when it stops going up. Add one. Add one. Add one. Stuck.

That number is so large, though, that even I didn’t have the patience to wait for the loop to end. So I broke the problem up into two pieces.

First I set a variable to 1. I keep doubling it until I find a number that is the same as that number plus one. That’s my high limit and half that number is valid.

Then I do a binary search inside that range. The code looks like this:

    a=1;
    b=2;
    //find one that fails
    while (a!=b) {
        old=a;
        a+=a;
        b=a+1;
    }
    //do binary search
    low=old;
    high=a;
    while (high-low>1) {
        mid=parseInt((low+high)/2,10);
        a=mid;
        b=a+1;
        if (a==b) {
            high=mid;
        } else {
            low=mid;
        }
    }
    console.log(high);

The answer is 9007199254740992. Something over 9 quadrillion. Makes more sense why it would be a limit when you look at the number in hexadecimal. That’s 0x020000000000000.

That’s right. JavaScript can tell the difference between 9007199254740991 and 9007199254740992, but it thinks that 9007199254740992 and 9007199254740993 are the same. That falls out from the IEEE-754 double-precision floating-point spec that JavaScript uses to represent all numbers.

Remember that next time you want to write a for loop that counts to 10 quadrillion–it’s an infinite loop. You’ll never get there.

JavaScript Numbers Can Bite

Sooner or later, JavaScript’s numbers will bite you. They bit me in a probability function, and I didn’t even see it coming.

Maybe you took a probability and statistics class and learned about combinations and permutations. You may remember that the formulas for those involve factorials. Let’s take a look at my combination routine.

    //---------------------------------------------------------
    // Function: combinations
    //   returns the combinations of k objects from a set of n objects
    combinations=function(n,k) {
        function factorial(a) {
            return a<2 ? 1 : a*factorial(a-1);
        }
        return Math.round(factorial(n)/(factorial(k)*factorial(n-k)));
    }

Kind of an interesting looking function, isn’t it? When you find the number of possible ways that you can put together a k objects from a set of n objects, you need to do three factorial functions. Since I didn’t need factorial anywhere else, I stuffed it inside the combinations function.

But what’s the Math.round doing there? Aren’t we dealing with whole numbers here? Yep. In most languages, we’d explicitly declare the variables for this function to be integers, but that’s just not an option in JavaScript–all numbers in JavaScript are floating point numbers.

Trouble Ahead

So where do we run into trouble? If n is 23 and k is 2, combinations returns 253.00000000000003.

Even more frustrating is this answer because it’s one we can come up with off the top of our heads: If n is 24 and k is 23, we get 23.999999999999996.

What’s happening? Our numbers are growing so large in factorial that they can no longer be represented exactly in JavaScript. The solution? In this case, I fix the result with Math.round().

Playing Computer

But we can do better if we play computer with even a small case. Let’s take n=5, k=2;

combinations=(5*4*3*2*1) / ((3*2*1) * (2*1));
//largest number calculated is 120

That could be changed to

combinations=(5*4) / (2*1);
//largest number calculated is 20

A huge change. Much better. Three floating point operations rather than nine. Less chance for mischief.

Factorial is a well known function, and the combination formula is easy to write in terms of factorial, but that ease of representation comes at a huge computational cost, and in the case of JavaScript, sometimes a cost of precision.

If we rewrite the function to take advantage of this insight, we’ll be able to support much larger parameters before we run into trouble.

The General Idea

The solution to most of these problems is to rearrange the math so intermediate results don’t get as big.

This was a nasty problem to catch, because many results were calculated correctly. But it didn’t take long to come up with a couple solutions.

Welcome Mr. Future JavaScript Programmer

Your mission: You are a Web 4.0 programmer from the future. For some reason we cannot possibly comprehend, you have come back to 2008 to impregnate your grandmother.

While you’re here it’s crucial to your mission that you also write a Web 2.0 app. Difficulty? Working in our ancient dialect of JavaScript. Solution? Mascara.

No, you don’t wear it, you use it.

Mascara is a program that translates tomorrow’s JavaScript into today’s JavaScript.

It’s been mentioned in some of the big JS venues like here and here, but I’ve been watching since and the author is really knocking the cover off the ball with new releases. I want to make sure he gets the attention he deserves.

Here’s the site:

http://ecmascript4.com/

And here’s the blog where you can read his changelist:

http://blog.ecmascript4.com/

What’s This All About?

JavaScript moves slowly. Programmers are hesitant to use new features of the language until it shows up in all major browsers. You can’t just decide one day to move to the latest version. The version of JavaScript you have available depends on the browser that your client has installed.

Now, if you’re working on an Intranet, or on a Point-of-Sales system, you can mandate the browser. But for applications written for the web, you have to wait, and wait, and wait. Even after all that waiting, some people still haven’t managed to upgrade from IE6 yet. So you roll your eyes and wait some more.

One solution is to check to see if some language features are missing and provide them yourself (there are JavaScript libraries designed to help you out). That works fine when methods are missing, but it doesn’t work for new syntax.

What Mascara does it take future JavaScript (ECMAScript 4) and translate it into current JavaScript. It also does compile-time error checking.

Way to go We can all be future JavaScript programmers now.

You Could Lose Your Mind

What happens if you initialize an object with the same key (name) twice? I tried it in FireFox, Internet Explorer, Safari, and Opera.

In all cases, the last assignment (the rightmost one) is the winner.

var obj={a:1,b:2,a:3,b:4};

You end up with an object like this:

{a:3,b:4}

I’m not sure that’s mandated by the language spec. It might depend on the implementation. Anyone know?

Missing and Default Parameters in JavaScript

Passing parameters to JavaScript functions seems simple enough. Since the language is weakly-typed, all the parameters in the call are simply comma-separated.

And in the definition of the function it can get no more complicated than that–a comma-separated list of parameters.

Not much room for flexibility, is there?

But let’s take a closer look. Suppose you don’t pass all the parameters that a function is expecting. What happens?

If you shortchange a function, all the parameters you failed to supply are undefined.

What happens if you give more parameters than the function expects? They are ignored, but you can find they are still accessible in an array-like list called arguments. (No, it’s not an array. While it does have a length, it’s missing the methods that come with arrays.)

Now What?

So we’ve revealed a bit of flexibility–JavaScript won’t come to a screaming halt if you supply more or less parameters than a function expects. It’s more flexible in handling parameters than we might have suspected.

Some languages allow you to specify default parameters. Can JavaScript do that? Well, it’s not in the spec, but JavaScript programmers commonly provide default parameters using JavaScript’s || operator.

a = a || 1;

If a is undefined, a will be assigned 1. A will also be assigned 1 if a is 0. That’s not always what you want, so sometimes a condition is best:

if (a===undefined) {
  a=1;
}

Let’s try one. We’ll make a function that takes three parameters.

  • a will have the default value of 1
  • b will have the default value of 2
  • c will have the default value of 3
function test(a,b,c) {
    a=a||1;
    b=b||2;
    c=c||3;
    console.log(a,b,c);
}

We can call it like this:

test(1,2,5);
test(undefined,3,undefined);
test();

And get output like this:

1,2,5
1,3,3
1,2,3

If you have a lot of parameters coming in, that can get messy fast. Is there a better way?

There Is a Better Way

More than a few programmers have taken a stab at providing a nice default parameter implementation, and JavaScript is flexible enough to provide many ways to do it.

Most of these solutions feel over-engineered to me, so I spent some time thinking about the problem and came up with my own solution. I wrote a function called defaultHandler. This is going to be easy! Take a look:

    defaultHandler=function(defaults,params) {
        var i;
        for (i in params) {
            defaults[i]=params[i];
        }
        return defaults;
    }

We start with the “defaults” object that was passed in. Obviously, this holds all the default values for the parameters we expect to get passed in. Then we spin through everything that was passed in as a parameter and add it to the defaults, overwriting values when we run into identical keys.

Simple. Too simple, perhaps. The trick must be in how we use it. Is that it? Well, here’s an example.

    function test(obj) {
        var params=defaultHandler({a:1,b:2,c:3},obj);
        console.log(params);
    }

Hmm. Not much going on there, either. I told you this was going to be easy!

Here, I call our test function:

    test({a:5,x:"tuna"});
    test({});
    test({b:10,y:5});

And get the following output:

Object a=5 b=2 c=3 x=tuna
Object a=1 b=2 c=3
Object a=1 b=10 c=3 y=5

That’s all there is to it. Instead of passing parameters, we always pass in one single object that holds all the parameters.

In effect, we’re ignoring JavaScript’s “almost an array, but not really” parameter-passing system, and using a full-blown object to do the parameter passing work. Since objects can hold anything (numbers, booleans, arrays, objects, functions, probably even regex descriptions), nothing has changed except the packaging and naming of parameters. And we’ve gained tons of flexibility.

Come to think of it, you don’t even really need the default handler. That’s just a nice way of pruning down the parameters which need to be passed.

Why Would I Do This?

Imagine you’ve written an operating system. It has a nice windowing user interface. You have function calls like “OpenWindow” that take some parameters. In a later version of the interface you want to start adding parameters to the function.

It can get messy. You want to keep backwards compatibility so old applications don’t break. So maybe you have a slew of new functions like “NewOpenWindow.” Then you come out with another revision and you want to add still more parameters.

When it gets silly enough, you look for another solution. The Amiga guys solved this problem with taglists. Taglists were much like an object–a list of names and corresponding values. You only supply the parameters you want to.

That was the first time I saw this sort of solution. They added an OpenWindowTags() function and that solved the problem forever. Unfortunately, in the case of the Amiga, “forever” didn’t last very long.

It’s a great solution for APIs of JavaScript libraries. You can add new stuff in the future without breaking any old calls to your library.

A good rule of thumb is to use JavaScript’s normal parameter conventions whenever the number of parameters are small and it’s inconceivable that they might change. Otherwise, pass in an object.

In Which I Discover I’m More Interesting and Provocative in Spanish

Some terrific Spanish-speaking people linked to this blog. Thanks to all those English-as-a-second-language readers out there who take the time to work through a blog like mine.

Google’s delightful Spanish-to-English translation…

Dreaming in Javascript

The more I write JavaScript, but I’m sure thinking that the language domain. Just when I decide one way to do something, I can think of another way of doing amazingly better.

JavaScript is a language that seems to have grown up with the sun shining on him. While Java is the caretaker of the beach, blonde boat and surrounded by plastic boobs embobados, JavaScript is disturbingly mysterious maiden forest that you can barely glimpse for a moment while you open passage between blackberries and brambles.

Two assertions of the most intriguing blog Dreaming in Javascript. Undoubtedly he invented the word recommended.

They are quoting from The Object Slinger post. Who knew I had such a flair for writing in Spanish?

A Challenge

Over here on his blog, Thomas has this “neat little HTML encoding trick in JavaScript”:

I came across a really neat trick in javascript lately that actually goes ahead and kind of cheats in a very effective manor!

Here’s the problem with javascript, everytime you send information from a form to a server side script, such as with AJAX, with HTML brackets it will return an error.  You can either manually fix this, or use a really neat trick called “escape”

 function escapeHTMLEncode(str) {
     var div = document.createElement(’div’);
     var text = document.createTextNode(str);
     div.appendChild(text);
     return div.innerHTML;
 }

What this simple little function does is take the internal HTML conversion code from your browser and returns a string converted to HTML.  It’s an awsome trick with how simple it is.

See, you have to note that whenever a browser creates an element in javascript, and a text node is created, the browser will go ahead and make sure that string comes out as raw code, and not as HTML, thus the term textnode and not innerHTML.

Now if they only had a way to reverse it that was that easy. lol

If only. Well, I’m here for ya buddy. Yeah, turns out that browsers have a nifty little html escape/unescape machine built in, and we can harness that built-in power.

Sample HTML Conversions
< .......... &lt;
> .......... &gt;
& .......... &amp;

I spent some time in Firebug playing with innerHTML. Stuff a string into innerHTML, and angle brackets get turned into their HMTL codes in the innerText field.

Like Magic

Now stuff HTML codes into innerText and *POP*, out it come angle brackets in the innerHTML field. Fun! I took a bit more direct route and managed to turn this trick both ways.

    escapeHTMLEncode=function(str) {
        var div=document.createElement('div');
        div.textContent=div.innerText=str;
        return div.innerHTML.replace(/>/g,"&gt;");
    }

    unescapeHTMLDecode=function(str) {
        var div=document.createElement('div');
	div.innerHTML=str;
	return div.textContent || div.innerText;
    }

Safari Manages to Piss Me Off

Complications? I don’t need to tell you that IE causes trouble, do I? This time it’s by using the field textContent rather than innerText. We handle that in the escape by just creating both fields. What does it hurt? This is a phantom div that will never be attached to a page anyway. In the unescape we || them together. One of them will be undefined and || gives us the one that’s not.

IE always causes problems, so no surprise there. But this time Safari offends as well by leaving “>” unconverted. This is mystifying to me. I did some searching and sure enough, that quirk has pissed off some developers. We convert it by hand with a replace.

This is all loads of fun (I’m dancing in my chair from the thrill of it all), but it shows that any time you rely on the browser to do something, you need to remember that you’re relying on four major (and untold minor) browsers to carry a load. In this case, probably safest to make the conversions yourself with a string of chained replace calls.

True story.

Yeah, I can solve Rubik’s Cube. For some reason, my children are amazed by this.

~, !, +, & –

Does that headline look like a bunch of cussing to you? I was hoping it would be offensive.

I’m also looking forward to see how it’s covered by the tech aggregators like Digg and Reddit. And I want to see if perhaps people land here as the result of searching for a bunch of punctuation.

Mostly I wanted to talk about JavaScript types, and how you can convert from boolean to numeric and vice versa.

This is going to be a pretty freeform discussion. If you get bored jump right to the end–there’s a trick there that’s pretty useful.

Big Mistake. Big, Big Mistake

Douglas Crockford has often mentioned that the dual usage for the plus symbol is a mistake in JavaScript. He’s right. It’s used both for numeric addition and for string concatenation. This trips programmers up all the time and there’s just no excuse for it. No upside. Another symbol should have been used for string concatenation.

The common solution to this is to wait until you get tripped up, find which term is being mistaken for a string, and then use one of the functions that JavaScript provides that converts strings to numbers. I prefer to use yet another usage of the plus symbol to do that work. I use the unary version of plus.

For example:

num = 1 + +"2"; //num is assigned the value 3

See the space between the plus signs? Yeah, that’s critical. You don’t want to mistake those two pluses for the symbol ++, the increment operator.

A unary minus works too, if you happen to want the negated version.

num = 1 - -"2"; //num is assigned the value 3, again

There’s another cool use for the plus sign. It’ll turn true and false into numbers.

num=+true; // num is 1
num=+false; //num is 0
num=-true; // num is -1
num=-false; //num is 0

So we turn true and false into 1 and 0 with unary plus. How do we turn 1 and 0 into true and false? One way is with the bang (exclamation point). In this case, we actually use a double-bang or “bang bang.” (Google “bang bang cher” and find out that long before William Hung banged, Cher banged.)

bool = !!1; //bool is true
bool = !!0; //bool is false

The first bang casts from the number to a Boolean, and the second undoes the logical not that was performed by the first bang.

You still following? How about a curve ball?

num = 1 + ~~"2"; //what the hell is that?

Welcome to the tilde. The result is 3 again, but what’s with the squiggles? The squiggle, of course, is the tilde operator. JavaScript programmers learn it and then promptly forget about it. But it plays a part in one of my favorite JavaScript tricks. We’ll see that right at the end. For now, let’s look at what it does to some values.

console.log(~-2); //1
console.log(~-1); //0
console.log(~0); //-1
console.log(~1); //-2
console.log(~2); //-3
console.log(~true); //-2
console.log(~false); //-1

As you can see, ~ is doing -(N+1). For fun, let’s throw a unary minus into the mix.

console.log(-~-2); //-1
console.log(-~-1); //0
console.log(-~0); //1
console.log(-~1); //2
console.log(-~2); //3
console.log(-~true); //2
console.log(-~false); //1

So -~N is the same as N+1.

Now let’s look at the bang symbol along with the tilde.

console.log(!-2); //false
console.log(!-1); //false
console.log(!0); //true
console.log(!1); //false
console.log(!2); //false
console.log(!true); //false
console.log(!false); //true

And for fun, let’s put the bang and the tilde together…

console.log(!~-2); //false
console.log(!~-1); //true
console.log(!~0); //false
console.log(!~1); //false
console.log(!~2); //false
console.log(!~true); //false
console.log(!~false); //false

Now that’s interesting. Only the value -1 makes it out alive with a true value. And come to think of it, there’s something special about -1. It’s a common sentinel value returned by functions that return indexes (JavaScript’s indexOf() is a great example, but you may have your own functions that return -1 as a sentinel value).

WTF?

What am I talking about? Suppose you want to know where the letter “s” is in a string. Well, you either get a number back that tells you where it is, or you get a -1 back telling you, hey buddy, no “s” in this string. So you end up with code like…

if (index>=0) {
 //found it
} else {
 //didn't
}

or

if (index>-1) {
 //found it
} else {
 //didn't
}

or

if (index!=-1) {
 //found it
} else {
 //didn't
}

But with what we now know about tilde, we can just do this…

if (!~index) {
 //found it
} else {
 //didn't
}

Or, finally, we can turn the logic around and do this…

if (~index) {
 //didn't find it
} else {
 //did
}

Credit

I’ve seen this trick a few times before. Add a comment to this post if you can help me find other places this has been mentioned.

Web Reflections

Immediate Execution

JavaScript functions are versatile. They are powerful and flexible and exotic like a carnival contortionist. It’s amazingly easy to get into trouble with them. Not just small trouble, but big-time Pinocchio-hanging-out-with-Lampwick trouble.

Here’s a great way to get sucked into some such trouble:

var i;
for (i=0;i<5;i++) {
    setTimeout(function() {alert('The number is '+i);},
               5000);
}

I think most programmers would expect this code to give you five alerts, and that the alerts would look like this:

The number is 0
The number is 1
The number is 2
The number is 3
The number is 4

But that’s not how it works. Instead, you get this:

The number is 5
The number is 5
The number is 5
The number is 5
The number is 5

What’s happening?

The inside function (the one in the setTimeout call) is a closure. A closure has access to its parent function’s variables, even after the parent function is done. In this case, we’re setting up five alerts. This happens very fast, before the first alert has executed. So by the time the alerts happen, the loop counter is 5.

So how do you fix this?

Well, the first answer is that it’s a dumb way to do it. You can pass setTimeout a string instead of a function and solve it that way, or just call one setTimeout and have that one call the next one.

But I’ve had a problem similar to this with click handlers on a series of buttons, so let’s go ahead and look at a real solution.

for (i=0;i<5;i++) {
  (function(num) {
    setTimeout(function() {alert('second '+num);},5000);
  })(i);
}

Huh? That looks crazy. Let’s figure it out.

Here’s a function.

function lert() {
    alert("Nope");
}

Here’s another function.

(function () {
    alert("Yep");
})();

What are the differences between them?

  • The first function has a name (the name is “lert”), while the second function does not have a name.
  • The first function does not execute until it’s called, but the second function executes immediately.

To get the immediate execution, we wrap the function in parentheses and follow it with another pair of parens. That’s just how it is–get used to it.

That’s how our solution works, except it needs to be a bit fancier because we need to pass a parameter in.

Quickie: Nameless functions in arrays

In JavaScript, you can write functions that look like this:

    function add(a,b) {
        return a+b;
    }

    function multiply(a,b) {
        return a*b;
    }

It’s the C way of writing functions, so it should look pretty familiar and comfortable. But it’s really just a short cut. There’s another way to write named functions.

    add = function(a,b) {
        return a+b;
    }

    multiply = function(a,b) {
        return a*b;
    }

If we like, we can put functions into objects.

ops={add: function(a,b) {return a+b;},
     multiply: function(a,b) {return a*b;}};

and now we can call the functions ops.add(a,b) and ops.multiply(a,b). Or, you can use another notation and call the functions with ops[“add”](a,b) and ops[“multiply”](a,b);

In a similar manner, because arrays can hold objects, we can do this:

ops=[function(a,b) {return a+b;},
     function(a,b) {return a*b;}];

I’ve stripped out the names of the functions and now they look like the anonymous functions that are so common in JavaScript. In this case we still have a way to call the function–by indexing into the array. Normally we create anonymous functions on the fly and bind them to an event like like a button click and never call the function directly in our code.

To get to these almost-anonymous functions I’ve defined in the array, call ops[0](a,b) or ops[1](a,b).

« Older entries Newer entries »