The Art of JavaScript

cf.Objective() 2013

Obligitory About me

Contact

Experience

What we'll cover

We will cover A LOT of ground! Please feel free to stop me in the halls, email me, or tweet at me to talk about any part of this presentation!

Let's Start With Some Basics

Numbers

All numbers in JavaScript are 64 bit floating point numbers.

Floating point arithmatic sometimes give strange results (http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html).


Operators

Comparisons

In JavaScript there are TWO sets of comparison operators;

Comparisons

What exactly is type coersion?


Always use === when comparing a variable 0, undefined, booleans, null, and empty strings "".

Checking if a variable is defined

Because of type coersion to check if a variable is truly defined or not it's best to check its type.

Logical Operators

Logical Operators

JavaScript OR Operator ||

The || operator returns the value of the first expression if it's true otherwise returns the value of the second expression.

Logical Operators

The || operator can be used to set default values.

var myFunc = function( arg ){

    var myVal = document.getElementById( arg ) || 
        document.createElement( "div" ); //defaultValue

        console.log( myVal );
};

myFunc( );
myFunc( "andor3" );

Logical

JavaScript AND Operator &&

The && returns the value of the first expression if it is false, otherwise it returns the value of the second.

Objects

Objects

Objects in JavaScript can be thought of as a set of key-value pairs.

myObject = { }; //empty object

myObject2 = {
    foo : "Foo", 
    bar : "Bar", 
    anotherObject : {
        baz : "Baz", 
        pez : "Pez"
    }
}; //this is called an object literal pattern

Objects

You can access an object's properties with "dot" notation or with associative array notation

Objects

When accessing properties from other properties in an object, use the this keyword.

Objects

To check if a property exists in an object use the hasOwnProperty() method or the in operator. hasOwnProperty will only search the current object for a property whereas in will search all the way up the prototype chain.

Functions

Creating Functions

Function Statement

function myFunc( args ) {
    ...     
};

Function Expression

Function expressions don't need to be named, these are called anonymous functions.

var myFunc = function( args ){
    ...     
};

Hoisting

There is one fundamental difference between function expressions and statements: hoisting.

Hoisting is when the JavaScript parser takes function and variable declarations and moves them to the top of the current scope.

Since JavaScript only has function scope, this means that they are moved to the top of the function they are delcared in.

Function Declaration Before Hoisting

function hoistingExample(){
    var firstVar;

    firstVar = "";

    var secondVar = "";
    
    secondFunction( firstVar + secondVar ); //OK

    firstFunction(); //ERROR

    var firstFunction = function(){
        //do something
    };

    function secondFunction(){
        // do another thing
    }
}

Function Declaration After Hoisting

function hoistingExample(){
    //function statements get moved to the top of the scope
    function secondFunction(){ 
        // do another thing
    }

    //variable declarations come next (but not the instantiation)
    var firstVar;
    var secondVar;
    var firstFun;

    //instantiation is left in place
    firstVar = "";

    secondVar = "";

    secondFunction( firstVar + secondVar );

    firstFunction();

    firstFunction = function(){
        //do something
    }
}

Lexical Scoping

Functions can be nested inside of other functions. Each nested function has access to the scope of all its parents.

Closures

Contrived Closure Example

var timesCalled = function(){
    var total = 0;
    
    return function(){
        total++;
        console.log( total );
    };
    
};

var callTimer = timesCalled(); //the closure is created here!

callTimer();

Constructor Functions

JavaScript has a special type of function called a Constructor function.

Constructor Functions

Constructor Functions

Create a new variable for our constructor function. Make sure the name starts with a capital letter!

var Robot = function( robotName ){
    this.robotName = robotName;
};

Constructor Functions

Now add a new property to the prototype of the constructor.

This is initialized with the prototype chain when the new keyword is used.

Robot.prototype.walk = function(){
    console.log( "Go " + this.robotName + " go!" );
};

Constructor Functions

Correct.

var robot = new Robot( "Ferbbot" );

Incorrect, not using the keyword does not create a scope or a prototype chain.

var anotherRobot = Robot( "Phineasbot" );

Constructor Functions

Without the new keyword when the constructor is called this is equal to the global object.

var Robot = function( robotName ){
    this.robotName = robotName;  //"this" actually equals the window object in a browser
};

This

This

The this keyword one of JavaScript's most mis-understood keywords (and one of it's most powerful).

var myObj = {
    myFunc : function(){ 
        console.log( this );
    }
};
        
var myFunc = function(){
    console.log( this );
};

myObj.myFunc();
myFunc();

This

What happened in the function call? Why did this point to window and not the function?

In order to explain we must understand what "this" means in JavaScript. This refers to the current execution context, or what OWNS the call to the function (think left side of function call).

When we called the myFunc function from within the object, the object was the current execution context.

When we called myFunc() from the root of the script tag, the window object was the current execution context

call() and apply()

The call(this,arg1,arg2,arg3,...) and apply(this,[args]) functions allow you to pass the value of this as the first parameter.

The difference is that the call function takes in any number of arguments whereas the apply function takes an array of arguments as its second argument.

This

Lets take a look at "this" when using a constructor function to create a new instance.

function Person( name ){
    this.name = name;
    
    console.log( this );
    console.log( this.name );
}

var person = new Person( "Bart" );

This In Object Literals

In an object literal this refers to the current object

This In Object Literals

Be careful when using this in nested functions!

var myObj = {
    firstName : "Homer",

    sayHello : function(){
        //look what happens when this is used inside a nested function
        return (function(){
            console.log( "Hello, " + this.firstName );
            console.log( this );
        }());
    }
};

myObj.sayHello();


In nested functions this refers back to global namespace!

This

For a much more comprehensive look at "this" and "function invocation" read:

Yehuda Kat's blog post: http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/

Scope In JavaScript: http://www.digital-web.com/articles/scope_in_javascript/

Inheritance

Inheritance is Implemented Through Prototypes

A prototype is just an object, both functions and objects have a hidden link to this object.

When a property is accessed the property is searched for on the object, then the objects prototype, then the prototype's prototype, etc

JavaScript stops looking up the chain when it reaches Object.prototype. If its not found undefined is returned.

Prototype's Members

Adding to an object's prototype link is "live". This means that properties added to a prototype are immediately accessable by all existing instances.

Inheritance

JavaScript uses a prototype-based inheritance model.

var Car = function( maker){ this.manufacturer = maker };

//add properties to Car's Prototype
Car.prototype = {
    wheels : 4, doors : 4,  manufacturer : ""
};

var Fusion = function(){ }; 

//set the Fusion's prototype to a new instance of car
Fusion.prototype = new Car( 'Ford' );

//reset the constructor property!
Fusion.prototype.constructor = Fusion; 

var fusion = new Fusion();

console.log( fusion.manufacturer );

Inheritance

First we create a new constuctor function.

var Car = function( maker){ this.manufacturer = maker };

//add properties to Car's Prototype
Car.prototype = {
    wheels : 4, doors : 4,  manufacturer : ""
};

Inheritance

Then we create a new, more specialized constructor function, setting its prototype to a new instance of our Car constructor.

var Fusion = function(){ }; 

Fusion.prototype = new Car( 'Ford' );

Notice that we use Fusion.prototype = new Car() and not:

var Fusion = function(){ 
    this.prototype = new Car( 'Ford' );
};

Setting this.prototype will just add a new property to each instance of Fusion.

Inheritance

Overriding an objects prototype also overrides a property called prototype.constructor.

Its important to reset this property, otherwise some things may stop working properly.

Fusion.prototype = new Car();

Fusion.prototype.constructor = Fusion; //reset the constructor

var fusion = new Fusion();

fusion.constructor === Fusion //true

Common JavaScript-Centric Design Patterns

Namespacing (Object Literal Pattern)

Namespacing is a way of not polluting the global namespace. It works great for smaller sized applications.

Its a quick and easy way to clean up a lot of code in the $(document).ready() callback.

Could be better...

$( function(){
    $( '#getUsers' ).on( 'click',function(){
        //get users
    } );

    var addUser = function(){
        //add
    }

    var userDiv = $( "#userDiv" );
} );

Namespacing

Better

var userApp = {
    $userDiv : null,
    $getUsers : null,

    init : function(){
         this.$userDiv = $( "#userDiv" );
         this.$getUsers = $( "#getUsers" );

         this.$getUsers.on( 'click',$.proxy( this,this.getUsers );
    },

    getUsers : function(){
        //get users
        this.addUser( user );
    },

    addUser = function( user ){
        this.userDiv.append( user );
    }
};

$( function(){
    userApp.init();
} );

Module Pattern

The module pattern can be used to "hide" variables and functions.

Options

The options pattern is a way to specify options and default values using a single argument.

$.fn.myPlugin = function( options ){
    var defaults = { color: "blue", height: "200px" };

    //remember to check the type of the argument!
    if( typeof options === 'object' ){
        options = $.extend( defaults, options );
    } else {
        options = defaults;
    }

    console.log( options );
};
    
$( document ).myPlugin( { color:'black', height: '500px' } );
$( document ).myPlugin();

Pub-Sub (AKA Observer)

The pub-sub pattern specifies that there are "publishers" that publish events, and "subscribers" that can subscribe to those events.

Pub-Sub (AKA Observer)

var contacts = {
    collection : [ 'Aaron', 'Drew', 'Tom' ],
    update : function(){
        this.collection[ 0 ] = 'Arian';
        this.collection[ 1 ] = 'Adrian';
        this.collection[ 2 ] = 'Ray';

        $( this ).trigger( 'change' );
    }
}; //publisher

$( contacts ).on( 'change',function(){
    //subscribers
    var contactSelect = $( 'select[ name="contact" ]' );
    contactSelect.find( 'option' ).remove();

    for(var i = 0; i < contacts.collection.length; i++){
        contactSelect.append( '<option value="">' + contacts.collection[ i]  + '</option>' );
    }
});

contacts.update();

Design Patterns

Be sure to check out Addi Osmani's "Essential JavaScript Design Patterns" open source book at: https://github.com/addyosmani/essential-js-design-patterns

Resources

Resources

You can get really good at JavaScript without spending a single penny!

This is where I used to mention "JavaScript the Good Parts", however "Effective JavaScript" by David Herman is one of the best JavaScript books I've read.

Giveaway Time!

What kind of car do I drive?

In this presentation we created a "Robot" constructor function that took a name as a parameter. What was the name of one of the robots we created?

Questions?

fin.

You can view this presentation online at:

http://bittersweetryan.github.com/art-of-javascript

/

#