Work In Progress

GoodParts

Objects

Simple Types:

  • number
  • string
  • booleans(true and false)
  • null
  • undefined
All other values are objects

number, string and booleans are object like in that they have methods, but they are immutable.

objects are mutable Keyed Collections.

Various object type

  • arrays
  • functions
  • regular expressions
  • objects

Properties

  • An object is a container of properties
  • Property has a name and value
  • Property name can be any string, including an empty string
  • A property can be any javascript value except undefined
  • No constraint on the name of a property or on the values of properties
  • A property name can be a keyword if it is in quotes

Javascript includes a prototype linkage feature that allows one object to inherit the properties of another. This reduces object initialization time and memory consumption.

Object Literals
  • 
    var another_empty_object = new Object();
    var empty_object = {};
    
  • 
    var stooge = {
        "first-name": "Jerome",
        "last-name": "Howard"
    };
    
  • A propertie's value can be obtained from any expression, including another object literal. Objects can nest:
Retrieval

Values can be retrieved from an object by wrapping a string expression in a [] suffix if the the string expression is a constant. a . notation can be used if it is a legal JavaScript name and not a reserved word.


stooge["first-name"] // "Joe"
flight.departure.IATA // "SYD"

The undefined value is produced if an attempt is made to retrieve a non existent member:


stooge["middle-name"] // undefined
flight.status // undefined
stooge["FIRST-NAME"] // undefined

Default


var middle = stooge["middle-name"] || "(none)";
var status = flight.status || "unknown";

Guard


flight.equipment //undefined
flight.equipment.model //throw "TypeError"
flight.equipment && flight.equipment.model //undefined

Update

If a property already exists, its updated


    stooge['first-name'] = 'Jerome';

if the object does not already exists the object is augmented


stooge['middle-name'] = 'Lester';
stooge.nickname = 'Curly';
flight.equipment = {
model: 'Boeing 777'
};
flight.status = 'overdue';

Reference

Objects are passed around reference. They are never copied.


var x = stooge;
x.nickname = 'Curly';
var nick = stooge.nickname;
// nick is 'Curly' because x and stooge
// are references to the same object
var a = {}, b = {}, c = {};
// a, b, and c each refer to a
// different empty object
a = b = c = {};
// a, b, and c all refer to
// the same empty object

Prototype

Javascript is a prototypal inheritance language. Generally in other languages with a type safe environment, a class can be derived by another class to get its data structure and behaviour. BUT there are no classes in javascript. JavaScript objects inherit data structure and behaviour from other objects. This is what we mean by a prototypal inheritance language and this is the difference between a classical and prototypal language.

Object comes with javascript. Now, every other object is linked to a prototype object from which it can inherit properties. All objects created from object literals are linked to Object.prototype. This means if i add another property or method to Object.prototype, all objects created from object literal notation will have access to that property or method.

Let's take an example to understand prototype. Take this piece of js code


var Animal = function (legs, animalSound) {
    this.legs = legs;
    this.makeSound = function () {
        console.log(animalSound);
    };
};

This shows that the prototype link has no effect on updating. When we make changes to an object, the object's prototype is not touched.

The prototype link is used only in retrieval. If we try to retrieve a property value from an object, and if the object lacks the property name, then JavaScript attempts to retrieve the property value from the prototype object. And if that object is lacking the property, then it goes out to its prototype, ans so on until the process finally bottoms out with Object.prototype. If the desired property exists nowhere in the prototyep chain, then the result is the undefined value. This is called delegation

The prototype relationship is a dynamic relationship. if we add a new property to a prototype, that property will immediately be visible in all of the objects that are based on that prototype.

Reflection

Enumeration

for in statement can loop over all of the property names in an object.

Use filters like typeof or hasOwnProperty to see what you want.

There is no guarantee in the order of the names. use for statement to have the same order as it was added. Also, it does not loop over prototype's properties.

Delete

Global Abatement

Create a single global variable. Like var MyAPP = {};. This will make sure that the variables of you application do not conflict with variables of other widgets, plugins etc.

Another way for Global availability is closure

Function Objects
  • Functions in JavaScript are objects.
  • Objects produced from object literals are linked to Object.prototype. But Function objects are linked to Function.prototype which happens to internally linked with Object.prototype
  • Every function is also created with 2 additional hidden properties
    • The function's context
    • The code that implements the function's behavior
  • Every function object is also created with a prototype property. This is different from the hidden link to Function.prototype. It's value is an object with a constructor property
  • Since functions are objects.
    • They can be used like any other value
    • stored in variables, objects and arrays
    • can be passed as arguments to functions
    • can be returned from functions
    • can have methods
Function Literal


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

If the function is not given a name it is said to be anonymous

A function literal can appear anywhere that an expression can appear. Functions can be defined inside of other functions. An inner function has access to its parameters and variables along with the variables of the function it is nested within. The function object created by a function literal contains a link to that outer context. This is called closure

Invocation
  • Invoking a function suspends the execution of the current function, passing control and parameters to the new function
  • two additional parameters are available
    • this
    • arguments
  • 4 patterns of invocation
    • Method invocation
    • Function invocation
    • Constructor invocation
    • Apply invocation
Method Invocation Pattern
When a function is stored as a property of an object, we call it a method. When a method is invoked this is bound to that object


// Create myObject. It has a value and an increment
// method. The increment method takes an optional
// parameter. If the argument is not a number, then 1
// is used as the default.
var myObject = {
    value: 0,
    increment: function (inc) {
        this.value += typeof inc === 'number' ? inc : 1;
    }
};
myObject.increment( );
document.writeln(myObject.value); // 1
myObject.increment(2);
document.writeln(myObject.value); // 3

this is available to the method with its the then state at the time of invocation.

Methods that get their object context from thisare called public methods

The Function Invocation Pattern

When a function is not the property of an object, then it is invoked as a function

this inside the function becomes the global object, usually Window object

Even in nested functions, the this does not becomes the actual object context.


var myObject = {
    value: 0,
    increment: function (inc) {
        this.value += typeof inc === 'number' ? inc : 1;
    }
};

myObject.double = function () {
    //var that = this; // Workaround.
    var helper = function () {
        console.log(this);
        //that.value = add(this.value, this.value);
    };
    helper(); // Invoke helper as a function.
};

But notice that double is a method because it is a property of myObject. And we remember in method invocation the this is the object context. So we can assign a variable specially to have an object that will hold the value of this. and pass that on to the inner function which is invoked as a function invocation


myObject.double = function () {
    var that = this;
    var helper = function () {
        console.log(that);
    };
    helper(); // Invoke helper as a function.
};

The Constructor Invocation Pattern

Functions that are intended to be used with the new prefix are called constructors

if a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member and this will be bound to that new object.


// Create a constructor function called Quo.
// It makes an object with a status property.
var Quo = function (string) {
    this.status = string;
};
// Give all instances of Quo a public method
// called get_status.
Quo.prototype.get_status = function ( ) {
    return this.status;
};
// Make an instance of Quo.
var myQuo = new Quo("confused");
document.writeln(myQuo.get_status( )); // confused

Use of this style of constructor functions is not recommended. We will see better alternatives in the next chapter

The Apply Incocation Pattern

Recall the method invocation pattern

This is similar to method invocation pattern, but that we can change the this object that will be used inside the method.


// Make an array of 2 numbers and add them.
var array = [3, 4];
var sum = add.apply(null, array); // sum is 7
// Make an object with a status member.
var statusObject = {
    status: 'A-OK'
};
// statusObject does not inherit from Quo.prototype,
// but we can invoke the get_status method on
// statusObject even though statusObject does not have
// a get_status method.
var status = Quo.prototype.get_status.apply(statusObject);
// status is 'A-OK'

Arguments
A bonus parameter that is available to functions when they are invoked. It gives the function access to all of the arguments that were supplied with the invocation, including excess argumetns that were not assigned to parameters.


// Make a function that adds a lot of stuff.
// Note that defining the variable sum inside of
// the function does not interfere with the sum
// defined outside of the function. The function
// only sees the inner one.
var sum = function ( ) {
var i, sum = 0;
for (i = 0; i < arguments.length; i += 1) {
    sum += arguments[i];
}
return sum;
};
document.writeln(sum(4, 8, 15, 16, 23, 42)); // 108

Return

A function always returns a value. if the return value is nto specified, then undefined is returned.

If the function was invoked with the new prefix and the return value is not an object, then this(the new object) is returned instead.


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


var Customer = function (name) {
    this.name = name;
    this.getname = function () {
        return this.name;
    }
    return {"name": this.name};
};

Exceptions

try, catch and throw is available


var add = function (a, b) {
    if (typeof a !== 'number' || typeof b !== 'number') {
        throw {
            name: 'TypeError',
            message: 'add needs numbers'
        };
    }
    return a + b;
}

// Make a try_it function that calls the new add
// function incorrectly.
var try_it = function ( ) {
    try {
        add("seven");
    } catch (e) {
        document.writeln(e.name + ': ' + e.message);
    }
}
try_it( );

Please note that "name" and "message" should not necessarily be "name" and "message". The name could have been "name2", "message2"

Augmenting Types
Any base function can add something to its prototype and it will be available to all who are new of this base function.
Recursion
TODO
Scope


var foo = function ( ) {
    var a = 3, b = 5;
    var bar = function ( ) {
        var b = 7, c = 11;
        // At this point, a is 3, b is 7, and c is 11
        a += b + c;
        // At this point, a is 21, b is 7, and c is 11
    };
    // At this point, a is 3, b is 5, and c is not defined
    bar( );
    // At this point, a is 21, b is 5
};

JavaScript has "functional scoping"

Closure

Inner functions get access to the parameters and variables of the functions they are defined within(with the exception of this and arguments)

Consider the case: a function returning a function.


var myObject = function () {
    var value = 0;
    return {
        increment: function (inc) {
            value += typeof inc === 'number' ? inc : 1;
        },
        getValue: function () {
            return value;
        }
    };
}();

This is a self calling anonymous function. It ran when the script loaded. myObject has 2 function properties increment and getValue

If you look at the definition of increment and getValue it uses value variable that was not actually defined within increment and getValue

We said JavaScript has functional scoping. So once the anonymous function ran and finished executing the value variable should not exist.

But increment and getValue still have a refernce of value variable when being executed.

What happened here was, when the self executing anonymous function executed and returned those 2 functions as a part of the properties, a snapshot of value was created and sent along with those functions. You can assume that there is a variable value inside the scope of both increment and getValue. These 2 methods share a scope which contains the hidden value variable. This scope is actually the context in which it was created.

This ability of JavaScript is called Closure

If you increment the value the hidden variable value increased. When i getValue then that same value is returned. This prooves that the hidden value variable is in a shared scope.

Callbacks

To freeze the page


request = prepare_the_request( );
response = send_request_synchronously(request);
display(response);

To not freeze the page


request = prepare_the_request( );
send_request_asynchronously(request, function (response) {
    display(response);
});

Note, the internal implementation of send_request_asynchronously decides how to call and get back a return value. This concept only displays what should be done to not freeze the page. Instead of getting back a response and waiting till we get back a response, pass the request and (what should be done when we get back a response)to the method and move on.

Module

A module is a function or object that is like an interface to do things and have states, but the implementation is hidden.

Take the example of a Module that makes serial number


var serial_maker = function ( ) {
// Produce an object that produces unique strings. A
// unique string is made up of two parts: a prefix
// and a sequence number. The object comes with
// methods for setting the prefix and sequence
// number, and a gensym method that produces unique
// strings.
    var prefix = '';
    var seq = 0;
    return {
        set_prefix: function (p) {
            prefix = String(p);
        },
        set_seq: function (s) {
            seq = s;
        },
        gensym: function ( ) {
            var result = prefix + seq;
            seq += 1;
            return result;
        }
    };
};

Notice these methods do not use this so it wont be possible to pass a differnt value of this via Apply Invocation.

Of course the complete method can be updated by another method, but it still does not reveals the implementation. Not clear

Notice if we pass the serialMaker.gensym method to another function, the user now won't be able to change the definition of set_prefix and set_seq. Instead he is only allowed to generate serial numbers.

Cascade

Some methods do not have a return value, it is typical for methods that set or change the state of an object to return nothing. If we have those methods return this instead of undefined, we can enable cascades. Common example is jQuery. Let's see this in code.


var Employee = function (id, name, rank) {
    this.id = id;
    this.name = name;
    this.rank = rank;

    this.increaseId = function () {
        this.id++;
    };

    this.nameChange = function (newName) {
        this.name = newName;
    };

    this.increaseRank = function () {
        this.rank++;
    }
}

Now, lets see cascading


var Employee = function (id, name, rank) {
    this.id = id;
    this.name = name;
    this.rank = rank;

    this.increaseId = function () {
        this.id++;
        return this;
    };

    this.nameChange = function (newName) {
        this.name = newName;
        return this;
    };

    this.increaseRank = function () {
        this.rank++;
        return this;
    }
}

Curry
TODO
Memoization
TODO