Javascript OOP

Custom Objects:

function Person(first,last) {
    this.first = first;
    this.last = last;
    this.fullName = function() {
         return this.first + " " + this.last;
    };
    this.fullNameReversed = function() {
         return this.last + ', ' + this.first;
    }
}
var s = new Person("Simon","Willison");

The 'new' keyword is strongly related to 'this'. The 'new' keyword creates a brand new empty object, and then calls the function specified with 'this' set to that new object. Functions that are designed to be called by 'new' are called constructor functions. Common practices is to capitalise these functions.

Every time we create a Person object, we are creating two new function objects within it - wouldn't it be better if this code was shared?

function personFullName() {
    return this.first + ' ' + this.last;
}
function personFullNameReversed() {
    return this.last + ', ' + this.first;
}
function Person(first,last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName;
    this.fullNameReversed = personFullNameReversed;
}

That's better: we are creating the method functions only once, and assigning references to them inside the constructor. Can we do better than that? The answer is yes:

function Person(first,last) {
    this.first = first;
    this.last = last;
}
Person.prototype.fullName = function() {
    return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function() {
    return this.last + ', ' + this.first;
}

Person.prototype is an object shared by all instances of Person. It forms part of a lookup chain: any time you attempt to access a property of Person that isn't set, javascript will check Person.prototype to see if that property exists there instead. As a result, anything assigned to Person.prototype becomes available to all instance of that constructor via this object.

This is incredibly powerful tool. Javascript lets you modify something's prototype at anytime in your program, which means you can add extra methods to existing object at run-time.

As mentioned before, the prototype forms part of a chain. The root of that chain is Object.prototype.

Remember how avg.apply() had a null first arguments? The first argument to apply() is the object that should be treated as 'this'.

The apply() function has a sister function named call, which lets you set 'this' but takes an expanded argument list as opposed to an array:

function lastNameCaps() {
   return this.last.toUpperCase();
}
var s = new Person("Simon","Willison");
lastNameCaps.call(s);
// Is the same as
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();

Javascript function declarations are allowed inside other functions. An important detail of nested functions in Javascript is that they can access variables in their parent function's scope:

function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}

This provides a great deal of utility for writing more maintainable code. If a function relies on one or two other functions that are not useful to any part of your code, you can nest those utility functions inside the function that will be called from elsewhere. This keeps the number of functions that are in the global scope down, which is a good thing. This is also a great counter to the lure of global variables. When writing complex code, it is often tempting to use global variables to share values between multiple functions - which leads to code that hard to maintain. Nested functions can share variables in their parent, so you can use that mechanism to couple functions together when it make sense without polluting your global namespace. This technique should be used with caution, but it's a useful ability to have.

Object oriented programming in javascript:

function Pet(name) {
   this._name = name;
}
Pet.prototype._name;
Pet.prototype.getName = function () {
   return this._name;
}
var p = new Pet("Max");
alert(p.getName());

Inheritance:

function Dog(name) {
   Pet.call(this,name);
}
Dog.prototype = new Pet();
Dog.prototype.wagTail = function () {
}
person = new Object ();
person.name = "Tim";
person.height = "6ft";
person.run = function() {
}

Creating object using literal notation (more robust):
timObject = {
    property1 : "Hello",
    property2 : "MmmMmm",
    property3 : ["mmm", 2, 3, 6, "aaa"],
    method1: function() {}
}
person = new Object ();
person.name = "Tim";
person.height = "6ft";
person.run = function() {
}

Creating object using literal notation (more robust):
timObject = {
    property1 : "Hello",
    property2 : "MmmMmm",
    property3 : ["mmm", 2, 3, 6, "aaa"],
    method1: function() {}
}

Preserving scope in JavaScript

page_revision: 0, last_edited: 1227373770|%e %b %Y, %H:%M %Z (%O ago)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License