Javascript 201

http://attheo.do

Node.js Meetup

Patterns? Hmm?

A design pattern identifies a common software development problem and provides a strategy for dealing with it.

Design Patterns are "Insurance Policies"

Design Patterns are proven to work.

Quantifying their value and how to enforce them

Don't buy "insurance" unless it offers some benefit.

Don't adopt a pattern unless it offers value that you can quantify and articulate to others.

Ask yourself, discuss with the team.

General Patterns

Lubing our way in...

Minimize Globals

Variables used without being explicitly declared with the var keyword

Actually they are not variables, they are properties of the global object.

Shared among all javascript code and increase probability of naming collisions.

Be a good "neighbour" in your neighbourhood

Minimize Globals

function() {
    var a = b = 0;
}
// same as ...

function() {
    var a = (b = 0);
}
function zeroFill(x, y) {
    angular = x >>> 2;
    return angular;
}

b leaks as a global property

Single 'var' Pattern

function lala() {

    var koko = 1
        , mama = 2
        , kaka = 3
        , obj = {
            tsoutsou: loulou
        }
        , mpe = 'mpou';

    // implementation [...]
}

Single 'var' Pattern

A single place to look for all local variables used in the function.

Prevents logical errors when a var is used before it's defined.

Helps you remember to declare variables and therefore minimize globals

Less code to type :)

Please cache your for loops

for (var i = 0; i < anArray.length; i++) {
    console.log(anArray[i]);
}

.length is accessed .length times

for (var i = 0, max = anArray.length; i < max; i++) {
    console.log(anArray[i]);
}

.length is cached!

Avoid Implied Typecasting

Javascript implicitly typecasts variables when you compare them

var flag = 0;
if (flag === false) {
    // I refuse to execute bro..
}

Avoid Implied Typecasting

Functions are Objects

var add = new Function('a, b', 'return a + b');
add(10, 10) // returns 20

Function Declaration Patterns

// Function Declaration

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

Usually, we don't do that.

Function Declaration Patterns

// Function Expression 
// a.k.a anonymous function

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

+ Intuitive: "function as an object"

+ Enforces good semicolon habits.

Function Declaration Patterns

// Named Function Expression

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

+ Debugger has explicit function name (stack trace)

+ Allows recursive functions: add can call itself

- Can break IE.

- Coffescript doesn't do it

Object Literals

// BAD
var o = new Object();
var a = new Array();
var s = new String();
var n = new Number();
var b = new Boolean();
// GOOD
var o = {};
var a = [];
var s = "";
var n = 0;
var b = false;

Function Patterns

Shit got real.

Callback Pattern

When you pass function A to function B as parameter

(function A is called a Callback)

Callback Pattern

function readHugeData(callback) {
  fs.readFile(pathToFile, function (err, data) {
    var bufferString = data.toString(); 
    callback(bufferString);
  });
}

// callback function
function logData(buffer) {
  console.log(buffer);
}

readHugeData(logData);

Arguments Control

Cause I don't want to remember your function signatures

Arguments Control

// BAD
function addPerson(firstName, lastName, age, location, address) {
    doShit();
}

addPerson('Thanos', 'Theodoridis', 30, 'Thessaloniki', 'Kapou 10');

// GOOD
var person = {
    firstName: 'Thanos',
    lastName: 'Theodoridis',
    age: 30,
    location: 'Thessaloniki',
    address: 'Kapou 10'
};

function addPerson(person) {
    doShit();
}

addPerson(person);

Returning Functions

Returning functions "remember" their environment plus they don't expose "private" vars

Returning Functions (Closures)

var counter = function() {
    var count = 0;
    return function() {
        return ++count;
    }
}

var increment = counter();

increment(); // returns 1
increment(); // returns 2
increment(); // returns 3

+ Closures encapsulate their environment (scope)

- Which is why you should be careful when creating closures in loops

Partially Applied Functions

Provide a number of arguments to a function, producing another function of smaller arity.

Partially Applied Functions

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

// partially apply this function with "a"
// set to 1
var partial = add.bind(null, 1);

// complete the function application by also
// providing "b"
partial(2); // returns 3

IIFE

Execute function as soon as its defined

IIFE

(function () {
    console.log('Bootstrap');
}());

+ Provides a scope sandbox.

+ Helps prevent variables and function       declaration make it to global scope

Memoization Pattern

Functions are objects, objects have properties. Use them to speed computations.

Memoization

var doSomething = function(param) {
    if(!doSomething.cache[param]){
        var result = {};
        // ... computation heavy operation
        doSomething.cache[param] = result;
    }
    return doSomething.cache[param];
};

doSomething.cache = {};

Object Creation Patterns

Paving the road to Object Oriented Javascript

Access Control

How to enforce private, protected and public properties/methods

Private Members ~> Closures

function Pet() {
    //private member
    var type = 'dog';
    // public getter
    this.getType = function() {
        return type;
    };
};

var indefix = new Pet();

console.log(indefix.type); // undefined
console.log(indefix.getType()); // "dog"

Private Members

Are we done yet?

Private Members

function Pet() {
    // private member (?)
    var petDetails = {
        type: 'dog',
        age: 20,
        color: 'black'
    };

    // public getter
    this.getPetDetails = {
        return petDetails;
    };
}

Passed by reference!!!

Access control & Object Literals

var myObject = (function (){
    // private properties
    var name = 'Thanos';

    // public getter
    return {
        getName: function() {
            return name;
        }
    }
}());

IIFE + Returning Functions!

Prototypes & Privacy

function Pet(){
    // private member
    var type = 'dog';
    
    // public function
    this.getType = function() {
        return type;
    };
}

Pet.prototype = (function () {
    // private member
    var food = 'Royal Canine';
    
    // public prototype member
    return {
        getFavFood: function() {
            return food;
        }
    };
}());

var indefix = new Pet();
console.log(indefix.getType()); // privileged "owned" method
console.log(indefix.getFood()); // privileged prototype method 

Private & Public Static Members

Static shit:

Those that don't change from one instance to another.

Used without having to create an instance of the "class".

Public Static Members

// constructor
var Pet = function() {};

// static method
Pet.isFriendly = function(){
    return false;
};

// normal method 
Pet.prototype.feed = function() {
    this.hungry = false;
};

// call static method
Pet.isFriendly(); // false

var indefix = new Pet();
indefix.feed();

Static Methods working with instances?

Pet.prototype.isFriendly = Pet.isFriendly;
pet.isFriendly(); // false

WARNING: Be careful when you use `this` inside the static method.

Private Static Members

Shared by all the objects created by the same constructor function

Not accessible outside the constructor

Private Static Members

var Item = (function() {
    
    //static variable
    var itemId = 0;
    
    // the new constructor implementation
    var NewItem = function() {
        ++itemId;
    };

    NewItem.prototype.getItemId = function() {
        return itemId;
    };

    return NewItem;

}());

var iPhone = new Item();
iPhone.getItemId(); // 1
var macbookPro = new Item();
macbookPro.getItemId(); // 2

BONUS!

The Chaining Pattern!

Enables you to call methods on an object one after the other

The Chaining Pattern

var obj = {
    value: 1,
    increment: function() {
        ++this.value;
        return this;
    },
    add: function(a) {
        this.value += a;
        return this;
    },
    log: function() {
        console.log(this.value);
    }
};

obj.increment().add(10).log(); // 12

// VS
obj.increment();
obj.add(10);
obj.log();

Thanks!

Copy of Javascript 102

By ibraimsap

Copy of Javascript 102

  • 260