KishCom

Developer. Gamer. Yo-Yo Thrower.

Modern JavaScript

Kind of a continuation of the JSON Gotcha post I wrote way back. I've been getting into JavaScript 1.8 (engines that implement ECMAScript 5). JavaScript implementations are tricky, it's a little like trying to deploy C code on different platforms with different compilers - this makes JavaScript in the browser kind of tricky to work with. Spidermonkey in FireFox works differently than V8 in Chrome, which works differently than Chakra (JScript) in Internet Explorer and SquirrelFish in Safari -- in addition to minor ECMAScript implementation differences they also have 'vendor specific' methods and differences that you must be aware of. As anyone who does web development with JavaScript can attest, this makes the mantra "write once, run everywhere" kind of tricky.


For all examples that indicate JavaScript 1.8 as a requirement, you need to wrap your code in script tags that identify your JavaScript as ECMA5. Since FireFox is the only browser that has released Javascript 1.8 support, this will only work with FireFox:

What's different with Javascript 1.8? Lots of little things, things that might make you go: "Huh? Oh. OHHHH COOL!" (in that order). One thing that is going to be bad practice at most shops, but is possible with 1.8 is implicit curly braces and return statements:
//Javascript 1.6 - What you're used to:
function somefunction(x){ return x * x; }

//Javascript 1.8 - More of a typical Lambda notation style
function somefunction(x) x * x;

Let's get into it! Look at this switch statement! It's not the same syntax as you might be used to, but it is similar. Take notice of the implied return and curly brackets on the Switch() function:
function Switch(i) arguments[++i];
console.log(Switch(3, 'dogs', 'cats', 'kittens', 'knives', 'chainsaws'));
//Logs 'knives' (remember, everything in JavaScript is 0-indexed)
console.log(Switch(1, 'dogs', 'cats', 'kittens', 'knives', 'chainsaws'));
//Logs 'cats' (remember, everything in JavaScript is 0-indexed)

Check out these lazy type-casts, not specifically JS1.8 related, but I wanted to share them none-the-less:
function toBoolean(x) !!x //Clever, short sweet. 

function toInt(x) x && + x | 0 || 0; // (this snippit explained at http://wtfjs.com/2010/12/06/convert-to-integer )

Let there be LET. One of the cooler keywords that became available in JavaScript 1.7 is the LET command. It is essentially a way to declare variables in a very local scope. Declared inside a block, the LET instantiated variables scope is only for that block. Declared outside a block, it applies for that statement only. Take a look:
//Inline
var derp = 42;
let (derp = "forty two") alert(derp); //Alert box displays "forty two"
alert(derp); //Alert box displays 42

//Inside a block (in this case, an IF statement)
var variableX = 42;
console.log(variableX); //42
if (variableX == 42){
    let variableX = "aww yeah";
    console.log(variableX); //"aww yeah";
}
console.log(variableX); //42

If you work with Python, the next example will make you smile. JavaScript 1.7 has generator expressions! Including a YIELD statement. This leads to all kinds of fun, easier to read code. Let's use the same example I used back when I talked about learning generators with Python. It's the second problem on the Project Euler site:
function fibGen(){
    var fibSeq = 0, prev = 1, prevPrev = 0;
    while(true){ //Required or you'll get: uncaught exception: [object StopIteration]. AFAIK defines the bounds of each yield
        [fibSeq, prevPrev] = [prev + prevPrev, prev];
        prev = fibSeq; //See next line. More on this in the next example
        //[fibSeq, prevPrev, prev] = [prev + prevPrev, prev, fibSeq]; // This doesn't work as intended. Why?
        if ((fibSeq % 2) == 0){
                yield fibSeq;
        }
    }
}
fib = fibGen();
var fibSum = 0;
while (fibSum < 3524577){
    //var nextFib = fib.next(); //Normally we'd just use this
    var nextFib = fib.send(undefined); //The send() method allows you to move to an iteration on any active generator
    fibSum += nextFib
}
console.log(fibSum); // Looking for 4613732 here
Another 'borrowed' idea from Python is array/list comprehensions. When I first came across them it was being used like this (which may not be right - see my attempted usage in the above example):
var herp = 42;
var derp = 420;
var slurp;

[herp, derp, slurp] = [10+10, 100, herp+derp];

console.info(herp); //20
console.info(derp); //100
console.info(slurp); //462

I just thought it was a novel way to manipulate multiple variables on the same line -- However, they are far more powerful:
function range(end){ for (var i = 0;  i <= end; i++) yield i }
var s = [2 * i for (i in range(100)) if ((i * i) > 3)]
console.log(s); //Now an is an array that
//starts at 4 (because of the if statement at the end) and that is
//counting by 2s (because of the i*2 at the start of the statement) and
//goes up to 200 because of the 100 passed to the range function
The last item I want to take a look at is direct manipulation of the __iterator__ object. In normal usage you would never see iterator objects, instead opting to use JavaScript's for ... in and for each ... in statements.
var someObject = {derp: "42", herp: "420", slurp: "100", merp: "forty two"};
for (var i in someObject){ //Loops over object names
    console.log(i); //Shows: derp, herp, slurp... etc
    console.log(someObject[i]); // Shows: 42, 420, 100... etc
}
//For each ... in loops over an objects properties not their names
for each (var i in someObject){
    console.log(i); // Shows: 42, 420, 100... etc
    console.log(someObject[i]); //undefined
}

That's great for looping over things in a linear fashion. What if we want to manipulate the iterator object? Lets get access to iterator object:
var someObject = {derp: "42", herp: "420", slurp: "100", merp: "forty two"};
var it = Iterator(someObject);
console.info(it); //iterator object only! You see nothing from someObject
//And call it a bit differently using the .next() and StopIteration exception
try{
    while(true){
        let currentResult = it.next(); //it.next() returns us a little array
        console.log(currentResult);//Looks like this: ["derp", "42"]
        //Up where we delcare "it" if we used: var it = Iterator(someObject, true); we'd get just the object names (no array)
    }
} catch (error if error instanceof StopIteration){
    console.log("End of record.");
} catch (error){
    console.log("Unknown error:" + error.description);
}

Armed with this knowledge we can do something cool like override the iterator object of JavaScript's Number object:
for (let i in 5){ //This on its own does nothing since JavaScripts Number object doesn't have an iterator object
    console.log(i); //You get nothing!
}

/* SNIP */

//Let's give the JavaScript native Number object an iterator:
Number.prototype.__iterator__ = function() {
    for ( let i = 0; i < this; i++ ){
        yield i;
    }
};
for (let i in 5){
    console.log(i); //This now logs 1 through 5! Cool right?!
}
This is hardly a definitive list, there is so much more cool JavaScript stuff I came across while writing this. I'll for sure write another one of these types of posts soon.
Back to KishCom.com
KishCom.Com

Table of Contents