Thursday 6 June 2013

JavaScript; not your regular curly brace language

JavaScript. It's the language of the web.

It's also a language originally created in 10 days, so there's a few warts here and there.

Here's my choice of JavaScript behaviours that might be a bit odd if you're expecting it behave like Java/C#!

Types

JavaScript is a dynamic and weakly-typed language. What does this mean in practice coming from a Java/C# world?

It's perfectly valid to assign anything to a variable.

var a = 'string';
a = 4;
a = [];

JavaScript won't interpret the assignments as errors, and it's caveat emporium to consumers as there's no way to specify the types of objects you'd like to receive.

JavaScript will use objects in ways you might not expect.

7 + '7' 
> '77'

7 * '7'
> '49'

7 * []
> 0

Equality Operators


== and != don't do what you think. In JavaScript, != and == perform type conversion first, and then compare the objects.

3 == '3'
> true

1 == true
> true

0 == []
> true

If either argument is a number or a boolean, then both operands are converted to a number first, then compared. If either argument is a string, then both operands are compared as strings.

Avoid this weirdness, train yourself to use === and !==. Both === and !== check objects are of the same type first and do no jiggery-pokery converting their arguments. In the comparison examples above, using === returns the expected value false.


Scope

Coming from a previous curly brace language, you'll probably be used to declaring variables as late as you need them. JavaScript doesn't like that.

function foo() {
    if (true)
    { var a = 3; }
    return a;
}

foo();
> 3

You may have expected the inner declaration of a to hide the outside declaration (i.e. a would be undefined). Not true. JavaScript does not have block scope. JavaScript treats variables declarations as if the appeared at the top of the declaring element (e.g. the function).


The logical operators, || and && and !

In Java and C#, the Boolean operators && and || return a Boolean result. In JavaScript the rules are again somewhat different.

3 || 4
> 3

undefined || 'banana'
> 'banana'

'fish' && 'chips'
> 'chips'

|| returns the first argument that evaluates to true.

&& returns the second argument if the first evaluates to true, otherwise the first argument.

! returns either the result of evaluating its argument. If you want to change an object to a Boolean representation the idiomatic way is to use !! to turn it to a Boolean first, and then complement it.

|| acts similarly to C#'s null coalescing operator ??.

function bar(foo) {
   foo = foo || 'banana';
   return 'baz_' + foo;
}

bar();
> 'baz_banana'

bar('bar');
> 'baz_bar'

Objects

There's no such thing as a class in JavaScript. Object definitions are much "looser" than they are in Java/C#.

Object constructor functions are simply defined as functions. By convention function names that represent constructors start with a Capital letter (unless you invoke using new they aren't very useful).

function I_Make_Objects() {
    var counter = 0;
    this.Property = 'I am a property';
    this.Method = function() {
        return 'Method' + counter++;
    };
}

I_Make_Objects();
> undefined

new I_Make_Objects();
> I_Make_Objects {
   Property: "I am a property", 
   Method: function
  }

var a = new I_Make_Objects();
> undefined    

a.Method();
> "Method0"

a.Method();
> "Method1"

JavaScript functions are actually kind of cool. As the simple example above shows, you can create objects with local state and use closures to hide this data from the outside world, providing you with a measure of encapsulation. Objects are simply represents as a bag of properties and closures.

Inheritance

In Java/C#, inheritance is class-based. Objects are instances of classes and an object can not change its class. In JavaScript, there are no classes, there are only objects. JavaScript uses prototypical inheritance; each object constructor has a prototype that describes the basic set of behaviours (also known as differential inheritance).

String // the object constructor for Strings
> function String() { [native code] }

String.prototype // the prototype of string
> String {}

"wibble".wibble();
> TypeError: Object wibble has no method 'wibble'

String.prototype.wibble = function () {
  return "wobble";
}
> function() { return wobble; }

"wibble".wibble();
> wobble()

By changing the prototype all objects constructed will now have that behaviour available. This is in contrast to the fixed nature of C#/Java where adding new behaviour at runtime is much more challenging.

Constructing an object assigns a prototype to the special property __proto__. Continuing the previous example:

"wobble".__proto__
> String { wibble: function }

Invoking a method on an object first searches for a match on the object itself and if that fails the JavaScript runtime searches up the prototype chain until it finds an object that has the requested property or method (Object is the only object without a prototype).

"wibble".__proto__
> String { wibble: function}

"wibble".__proto__.__proto__
> Object {}

"wibble".__proto__.__proto__.__proto__
> null

Prototypes are a fantastical flexible way of adding and removing behaviour at runtime. For example, you could redefine the prototype of string to give access to a common set of methods.