OOP

  • Objects are also associative arrays (hashes).
  • Object members can be accessed using array syntax.
obj.data
obj.foo()
obj['data']
obj['foo']()

JSON

myObj = { name1:value1, name2:value2, ... }
  • JavaScript Object Notation
  • A subset of the JavaScript object literal notation
  • Useful for sending structured data; simpler and faster than using XML
  • Can be used for CSI (client-side includes)
  • The same syntax is used for associative-array literals.
var myObj = {
    myInt: 1,
    myArray1: ["yellow", "green"],
    myArray2: {"lemon":"yellow", "lime":"green"}
}
Object to string
var myJSONText = JSON.stringify(myObject);
String to object
var myObject = eval('(' + myJSONtext + ')');   // Fast
var myObject = JSON.parse(myJSONtext);         // Faster (if natively supported) and safer

Object literals

var myObj = {
    data: 1,
    foo: function() {...} 
};
  • JavaScript object literal notation
  • Encapsulated by curly brackets with zero or more property and value pairs, separated by commas
  • Each property and value is separated by a colon
  • Property names can be identifiers, strings, or numbers
  • Values can be strings, numbers, functions, or other objects
var myObj = {
    // Properties
    myInt: 1,
    myStr: "",
    myBool: false,

    myArray1: [],
    myArray2: ["yellow", "green"],
    myArray3: {0:"yellow", 1:"green"},
    myArray4: {"lemon":"yellow", "lime":"green"},

    // Methods
    foo: function() { return this.myInt; },
    bar: function(args) { ... }
}

var x = myObj.foo();
var y = myObj["foo"]();

Object templates

function MyObject() {
    this.data = 1;
    this.foo = function() {...};
}
  • aka object constructors, constructor functions, constructors
  • Functions can be used as a template for new objects
  • An object template is often referred to as a class
function MyObject(args) {
    // Properties
    this.myInt = 1;
    this.myArray = new Array();

    // Methods
    this.foo = function() { return this.myInt; }
    this.bar = function(args) { ... }
}

# Instantiating the Object
var myObj = new MyObject();
var x = myObj.foo();

Instantiating objects

  • The following are equivalent:

Object literal

// Object literal
var myObj = {
  num: 30,
  foo: function() {}
}

Object template

function MyObject() {
  this.num = 30;
  this.foo = function() {}
}
var myObj = new MyObject();
// Anonymous object template
var myObj = new function() { ... }
// Named object template (easier to debug when it's not anonymous)
var myObj = new function MyObject() { ... }

Adding properties and methods on-the-fly

var myObj = new function() {};
myObj.num = 30;
myObj.foo = function() {};
var myObj = new Object(); ...

new operator

  • When using the new operator, parentheses are optional when calling an object template with no arguments
function MyObject() {...}

obj1 = new MyObject();
obj2 = new MyObject;
  • The difference between an object template (class) and a regular function is that an object template is called using the "new" keyword, which creates a new instance of the object template (class)
  • If an object template is called without the "new" keyword, it is run as a regular function, and "this" refers to the global object (which in browsers is the same as "window")
function MyObject() {
  // If "new" was omitted, correct the problem
  if (!(this instanceof MyObject)) { return new MyObject(); }
  ...
}
function MyObject() {
  // If "new" was omitted, raise an exception
  if (!(this instanceof arguments.callee)) { throw Error("Constructor called as a function"); }
  ...
}

Properties

function MyObject() {                   // Access level      Internal       External
    var a = 1;                          //   Private           a              n/a
    this.a = 1;                         //   Public            this.a         obj.a
}
MyObject.prototype.a = 1;               //   Prototype         this.a         obj.a
MyObject.a = 1;                         //   Static            MyObject.a     MyObject.a

Private

var myVar = 50;
  • aka private variables
  • Private properties can be accessed within a privileged or private method (without using this).
  • To access private data, the methods have to be defined within the same closure as the private data.
  • Constructor parameters remain available as implicit private properties.

Public

this.data = 1;
  • Public properties can be accessed within a public or privileged method using this.
  • Public properties can be accessed externally using the name of the object instance.

Prototype

MyObject.prototype.data = 1;
  • Added for each instance of the object, even those that have already been created
  • Are not static
  • Prototype properties can be accessed within a public or privileged method using this.
  • Prototype properties can be accessed externally using the name of the object instance.

Static

MyObject.data = 1;
  • Static properties can be accessed within a public, privileged, private, or static method using the name of the object template.
  • Static properties can be accessed externally using the name of the object template.

Methods

function MyObject() {                   // Access level       Internal           External
    function foo(){};                   //   Private            foo()              n/a
    var foo = function(){};             //   Private            foo()              n/a
    this.foo = function(){};            //   Privileged         this.foo()         obj.foo()
}
MyObject.prototype.foo = function(){};  //   Public             this.foo()         obj.foo()
MyObject.foo = function() {};           //   Static             MyObject.foo()     MyObject.foo()

Private

function foo1() {...}         // Shorthand syntax
var foo2 = function() {...}
  • aka private functions
  • Private methods can be accessed within a privileged or private method (without using this).
  • Private methods can access private and static properties and methods.
  • Private methods lack an implicit this variable for accessing additional properties and methods

Privileged

this.methodName = function() {...};
  • Privileged methods can be accessed within public or privileged methods using this.
  • Privileged methods can be accessed externally using the name of the object instance.
  • Privileged methods can access private, public, prototype, and static properties.
  • Privileged methods can access private, public, privileged, and static methods.
  • Unlike public methods, privileged methods are able to access private properties and methods, unless they're defined outside of the object template.
obj.methodName = function() {...};    // Defined externally; cannot access private properties and methods

Public

MyObject.prototype.foo = function() {...}
  • Added for each instance of the object, even those that have already been created
  • Are not static
  • Public methods can be accessed within a public or privileged method using this.
  • Public methods can be accessed externally using the name of the object instance.
  • Public methods can access public, prototype, and static properties.
  • Public methods can access public, privileged, and static methods.
  • Public methods are unable to access private properties and methods.

Static

MyObject.foo = function() {...}
  • Static methods can be accessed within a private, public, privileged, or static method using the name of the object template.
  • Static methods can be accessed externally using the name of the object template.
  • Static methods can only access static properties and methods.

Inheritance

function Parent() {}
function Child() {}

Child.prototype = new Parent();        // Specify that Child inherits from Parent
Child.prototype.constructor = Child;   // Reset the constructor property; otherwise, instances
                                       // of Child would have a constructor of Parent.
// Call an overridden parent method from within a child method, using the context of the child object.
// Any parameters for the function go after "this".

Parent.prototype.foo.call(this); // Parent method must be a public (prototype) method

Tricks to simplify inheritance

parent

// Define a makeshift "parent" property to abstract the name of the parent (note: "super" is a reserved word)

Child.prototype.parent = Parent.prototype;
...
this.parent.foo.call(this);

inheritsFrom

// Extend the Function object

Function.prototype.inheritsFrom = function(parentClass) {
    this.prototype = new parentClass;
    this.prototype.constructor = this;
    this.prototype.parent = parentClass.prototype;
    return this;
}
...
Child.inheritsFrom(Parent);

In-depth

Efficiency

  • The following members are instantiated for each new object: private and public properties, private and privileged methods (i.e. non-static, non-prototype).
  • Only one copy exists for static and prototype properties, and static and public (prototype) methods.
  • When a prototype property is modified through an object instance, a new public property is created for that object instance (i.e. copy-on-write).
MyObject.prototype.data = 1;    // Define prototype property
obj.data = 2;                   // Create a public property for the modified value (if not already done)
MyObject.prototype.data = 3;    // Modify existing prototype property
  • Public methods are more memory-efficient than privileged methods, but they force the use of public properties (rather than private ones), which makes them less robust (vulnerable to inappropriate external modification).

Private data

  • To access private data, the methods have to be defined within the same closure as the private data.
  • This also applies for accessing private methods.
  • Private data is defined within an object template, cannot be accessed externally, and can only be accessed by methods defined within the object template.
  • This helps avoid inappropriate use or modification of private data and methods.

Private methods

  • Private methods lack an implicit this variable (for accessing public and prototype properties, and public and privileged methods)
  • This is due to an error in the ECMAScript specification which causes this to be set incorrectly for inner functions
  • Can't define an explicit this parameter or variable, since this is a reserved keyword, and in browsers there's already a default this variable that refers to the window object
  • Could optionally store the value of this in a private property ( _thisself, that, ...)
var _this = this;   // Private methods can use "_this" as an alias for "this"

Public methods

  • Public methods can be used as wrappers for privileged methods which can then access private properties and methods (so long as the privileged methods are defined within the object template).
this.innerFoo = function() {...};                                 // Privileged method
...
MyObject.prototype.foo = function() { return this.innerFoo(); }   // Call the privileged method

Design patterns

Singleton pattern

var obj = new function() { ... }             // Anonymous object template
var obj = new function MyObject() { ... }    // Named object template (easier to debug)
function MyObject() {                        // Private object constructor

    // If the constructor was not called by the getInstance method
    if (MyObject.caller != MyObject.getInstance) {
       throw new Error("There is no public constructor for MyObject.");
   }
... 
}

MyObject.__instance__ = null;   // Static property

MyObject.getInstance = function() {   // Static method
    if (this.__instance__ == null) {
        this.__instance__ = new MyObject();
    }
    return this.__instance__;
}

var obj = MyObject.getInstance();   // Get the singleton object

 

Resources URL: 
notes/javascript/resources
Sources URL: 
notes/javascript/sources

See Also