JavaScript

Presenter Notes

bad-vs-good

Presenter Notes

The Bad Parts

  • Global Variables
  • Semicolon insertion
  • + adds and concatenates
  • typeof
  • with and eval
  • phony arrays
  • false, null, undefined, NaN
  • == and !=

Presenter Notes

The Good Parts

  • Loose Typing
  • Dynamic Objects
  • Object Literals
  • Functions (lambda)

Presenter Notes

JavaScript Types

  • Object
  • String
  • Boolean
  • Array
  • Date
  • RegExp

Presenter Notes

Objects

  • An object is a dynamic, mutable collection of properties
  • Every property has a key string that is unique within that object
  • Prototype linkage feature, that allows one object to inherit properties of another

Presenter Notes

get, set, and delete

// get
var name = object.name;
var name = object['name'];

// set
object.name = value;
object['name'] = value;

// delete
delete object.name;
delete object['name'];

Presenter Notes

Object literals

An expressive notation for creating objects:

var emptyObject = { };

var myObject = {
    'some property': 'some value',
    foo: bar,
    method: function(param) {
        // do stuff
    }
};

Presenter Notes

Prototype

  • Every object is linked to a prototype object from which it can inherit properties
  • All objects created from object literals are linked to Object.prototype

Presenter Notes

Prototype

var Person = function (name) {
    this.name = name;
};

Person.prototype.sayHello = function () {
    alert('Hello, my name is ' + this.name);
};

var thomas = new Person('Thomas');
thomas.sayHello();

Presenter Notes

Prototype

var Person = function (name) {
    this.name = name;
};

Person.prototype.sayHello = function () {
    alert('Hello, my name is ' + this.name);
};

var thomas = new Person('Thomas');
thomas.sayHello();

Person.prototype.sayMyName = function () {
    alert('Hello, my name is ' + this.name);
};

thomas.sayMyName();

Presenter Notes

Prototype Chaining

var Person = function () {
};
Person.prototype.sayHello = function () {
    alert('Hello, my name is ' + this.name);
};

var Customer = function (name) {
    this.name = name;
};

Customer.prototype = new Person();

var customer = new Customer('Customer');
customer.sayHello();

Presenter Notes

Numbers

  • Only one number type
  • double-precision 64-bit format IEEE 754 values
  • Math namespace for advanced operations

Presenter Notes

parseInt

alert(parseInt('123'));
alert(parseInt('010'));

Presenter Notes

parseInt

parseInt('123'); // 123
parseInt('010'); // 8

?!?

Presenter Notes

parseInt

parseInt('123'); // 123
parseInt('010'); // 8

?!?

parseInt('010', 10);
parseInt('11', 2);

Presenter Notes

parseInt

parseInt('123'); // 123
parseInt('010'); // 8

?!?

parseInt('010', 10); // 10
parseInt('11', 2); // 3

ALWAYS SPECIFY THE BASE

Presenter Notes

Strings

  • Sequences of unicode characters (16 bit)
  • Similar strings are equal (===)
  • Strings are objects
  • Strings are immutable

Presenter Notes

Booleans

  • true or false
  • 0, "", NaN, null and undefined are falsy
  • Everything else is truthy
  • Boolean operations: &&, || and !

Presenter Notes

Arrays

  • A special type of object; Keys are whole numbers
  • No need to provide type or length when creating an array

Presenter Notes

Array literals

An expressive notation for creating arrays

var array = ['one', 'two', {number: 'three'}, function() {}];

Presenter Notes

Array.length

var a = ['one', 'two'];
alert(a.length);

a[100] = 'three';
alert(a.length);
  • array.length is always one more than the highest index

Presenter Notes

Dates

var date = new Date('January 25, 2012');
date.getYear();     // 2012
date.getMonth();    // 0 ???
date.getDate();     // 25
  • The Date function is based on Java's Date class...

Presenter Notes

RegExp

if (myString.match(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/)) {
    // Great Success!
}

Presenter Notes

Functions

Presenter Notes

Functions are first class objects

  • May be passed as an argument to a function
  • May be returned from a function
  • May be assigned to a variable
  • May be stored in an object or array

Presenter Notes

Function literals

A function literal has four parts:

  • the reserved word function
  • optional name (which can be used to call itself in recursion)
  • optional parameters
  • set of statements wrapped in curly braces

Example:

// Create a variable called add and store a function
// in it that adds two numbers
var add = function(a, b) {
    return a + b;
};

// alternatively (but not quite the same as we'll see later)
function add(a, b) {
    return a + b;
}

Presenter Notes

Function invocation patterns

  • Method invocation pattern
  • Function invocation pattern
  • Constructor invocation pattern
  • Apply invocation pattern

These patterns differ in how this is initialized

Presenter Notes

Method invocation pattern

  • When a function is stored as a property of an object, it is called a method
  • When a method is invoked, this is bound to that object (late binding)

Example:

var myObject = {
    value: 0,
    increment: function(inc) {
        this.value += inc;
        alert(this);
    }
}

myObject.increment(2);

Presenter Notes

Function invocation pattern

  • When the function is not the property of an object, it is called a function
  • When a function is invoked, this is bound to the global object

Example:

var foo = function() {
    alert(this); // Window in the browser
};

foo();

Presenter Notes

This was a design mistake in the language. A consequence is that a method cannot employ an inner function to help it do its work because the inner function does not share the method's access to the object as its this is bound to the wrong value

Function invocation pattern

Example 2:

myObject.double = function() {

    var helper = function() {
        this.value = add(this.value, this.value); // this.value
                                                  // is undefined
    };

    helper(); // invoke helper as a function
};

myObject.double(); // invoke double as a method

Presenter Notes

Function invocation pattern

Example 2:

myObject.double = function() {
    var that = this; // workaround

    var helper = function() {
        that.value = add(that.value, that.value);
    };

    helper(); // invoke helper as a function
};

myObject.double(); // invoke double as a method

Presenter Notes

Constructor invocation pattern

  • If a function is invoked with the new prefix, a new object will be created with a hidden link to the value of the function's prototype member
  • this is bound to that new object
  • By convention, they are kept in variables with a capitalized name
  • Use of constructor functions is not recommended

Example:

// Create a constructor function called Foo
var Foo = function(string) {
    this.value = string;
    alert(this);
};

// Make an instance of Foo
var myFoo = new Foo('confused');
// Call Foo as an function
var myFoo = Foo('confused');

Presenter Notes

Apply invocation pattern

  • The apply method lets us construct an array of arguments to use to invoke a function
  • It lets us choose the value of this

Example:

var context = {};

var args = [3, 4];
var sum = add.apply(context, args); // this === context inside
                                     // the add function

var sum = add.call(context, 3, 4); // this === context inside
                                   // the add function

Presenter Notes

Hoisting

var myvar = 'my value';

function bar() {
    alert(myvar);
    var myvar = 'local value';
}

bar();

Presenter Notes

Hoisting

var myvar = 'my value';

function bar() {
    var myvar = undefined;
    alert(myvar); // undefined
    myvar = 'local value';
}

bar();

Presenter Notes

Hoisting

Function expression:

alert(add(2, 3));
var add = function(a, b) {
    return a + b;
};

Function declaration:

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

Presenter Notes

Hoisting

Function expression:

var add = undefined;
alert(add(2, 3)); // error
add = function(a, b) {
    return a + b;
};

Function declaration:

var add = function add(a, b) {
    return a + b;
};
alert(add(2, 3)); // 5

Presenter Notes

Hoisting

Takeaway:

  • Declare all variables at the top of your function
  • Declare all functions before you call them

Presenter Notes

Scope

var foo = 1;
function bar() {
    if (!foo) {
        var foo = 10;
    }
    alert(foo);
}
bar();

Presenter Notes

Scope

var foo = 1;
function bar() {
    var foo = undefined;
    if (!foo) { // true
        foo = 10;
    }
    alert(foo); // 10
}
bar();

Presenter Notes

Global Scope

function bar() {
    x = 10;
}
bar();
alert(x);

function foo() {
    var y = 10;
}
foo();
alert(y);

Presenter Notes

Global Scope

function bar() {
    x = 10; // Creates a global variable
}
bar();
alert(x); // 10

function foo() {
    var y = 10; // Creates a local variable
}
foo();
alert(y); // y is undefined

Presenter Notes

GLOBAL VARIABLES ARE EVIL!

Presenter Notes

Scope

Takeaway:

  • JavaScript has function scope, not block scope
  • If you forget the var keyword, you create a global reference
  • Never forget the var keyword

Presenter Notes

Closure

function foo(x) {
    var tmp = 3;
    function bar(y) {
        alert(x + y + (++tmp));
    }
    bar(10);
}
foo(2);
foo(2);
foo(2);

Presenter Notes

Whenever you see the function keyword within another function, the inner function has access to variables in the outer function. This will always alert 16, because bar can access the x which was defined as an argument to foo, and it can also access tmp from foo.

Closure

function foo(x) {
    var tmp = 3;
    function bar(y) {
        alert(x + y + (++tmp)); // 2 + 10 + 4 = 16
    }
    bar(10);
}
foo(2);
foo(2);
foo(2);

THIS IS NOT A CLOSURE

Presenter Notes

That is not a closure. A closure is when you return the inner function. The inner function will close-over the variables of foo before leaving.

Closure

function foo(x) {
    var tmp = 3;
    return function (y) {
        alert(x + y + (++tmp));
  }
}
var bar = foo(2); // bar is now a closure
bar(10);
bar(10);
bar(10);
bar(10);

Presenter Notes

This function will also alert 16, because bar can still refer to x and tmp, even though it is no longer directly inside the scope. However, since tmp is still hanging around inside bar's closure, it is also being incremented. It will be incremented each time you call bar.

Closure

Takeaway:

  • A closure in JavaScript is like keeping a copy of the all the local variables, just as they were when a function exited.

Presenter Notes

Patterns

Presenter Notes

Module Pattern

(function () {
    var privateVariable;
    function privateFunction(x) {
        // access privateVariable
    }

    GLOBAL.firstMethod = function (a, b) {
        // access privateVariable
    };

    GLOBAL.secondMethod = function (c) {
        // call privateFunction()
    };
}());

Presenter Notes

Revealing Module Pattern

var singleton = (function () {
    var privateVariable;
    function privateFunction(x) {
         // access privateVariable
    }

    return {
        firstMethod: function (a, b) {
             // access privateVariable
        },

        secondMethod: function (c) {
            // call privateFunction()
        }
    };
}());

Presenter Notes

Sandboxing

(function (window, undefined) {
    var document = window.document,
        $ = jQuery = window.jQuery.noConflict(),
        _ = window._.noConflict(),
        Backbone = window.Backbone.noConflict();

    var root = {};

    // ...

    window.root = root;
} (window));

Presenter Notes

Styles

Presenter Notes

Style Isn't Subjective

// Silent error
return
{
    ok: false
};

// Works well
return {
    ok: true
};

Presenter Notes

Style Isn't Subjective

return
{
    ok: false
};

Presenter Notes

Style Isn't Subjective

return; // semicolon insertion
{
    ok: false
};

Presenter Notes

Style Isn't Subjective

return;
{ // block
    ok: false
};

Presenter Notes

Style Isn't Subjective

return;
{
    ok: false // label
};

Presenter Notes

Style Isn't Subjective

return;
{             // useless
    ok: false // expression
};            // statement

Presenter Notes

Style Isn't Subjective

return;
{
    ok: false; // semicolon insertion
};

Presenter Notes

Style Isn't Subjective

return;
{
    ok: false;
}; // empty statement

Presenter Notes

Style Isn't Subjective

return;
{ // unreachable statement
    ok: false;
}

Presenter Notes

Styles

  • Use === and !==, not == or !=
  • Declare all variables before use
  • Declare all functions before use
  • Always use blocks with structured statements such as if and while
  • Variables and functions should start with a lower case letter
  • Constructor functions which must be used with the new prefix should start with a capital letter
  • Constructor functions should be avoided
  • Use {} instead of new Object(). Use [] instead of new Array()
  • eval is Evil
  • Don't use with
  • http://javascript.crockford.com/code.html

Presenter Notes

JSLint

Presenter Notes

Books

Good Parts

Presenter Notes