Object Oriented JavaScript

JavaScript Objects And Classes

1 Object Constructor

This is Anti pattern

var james = new Object();
james.name = "James Bond";
james.getName = function () {
        return this.name;
    };

2 Object.create Function

This is Anti pattern

var james = Object.create(null);
james.name = "James Bond";
james.getName = function () {
        return this.name;
    };
//General Syntax is
var obj = Object.create({prop: ...});

3 Object Literal Syntax

var james = {
    name: "James Bond",
    getName: function () {
        return this.name;
    }
};

4 Function Constructor

function Person(name) { 
        this.name = name; 
        this.getName = function() { 
            return this.name; 
        }; 
};
// OR
var Person = function (name) {
    this.name = name;
    this.getName = function () {
        return this.name;
    };
};
var james = new Person ("James Bond");
// Don't do this!
Person('James'); //=> undefined

4.1 Enforce New

function Person (name) {
    var that = {};
    that.name = name;
    that.getName = function () {
        return this.name;
    };
    return that;
}
//OR
function Person (name) {
    return {
        name: name,
        getName : function () {
            return this.name;
        };
    }
}

5 Sington

var james = new function (name) {
    this.name = name;
    this.getName = function () {
        return this.name;
    };
};

6 ES6 Syntax

class Person {
  constructor(name) {
    this.name = name;   
  }
  get name() {
    return this.name;
  }
}

JavaScript Prototype

 

In General you have to be cautious with :

  • What goes inside constructor function
  • what goes inside prototype
  • Be extra careful if you are putting properties in prototype

Properties and Methods

Objects created using constructor function will have its own copies of properties and methods. Further it will have prototype property, which will intern have constructor property and a chain of prototype property.

Method in Constructor Function

function Person(firstName, lastName) {
    this.firstName = firstName,
    this.lastName = lastName,
    this.fullName = function() {
        return this.firstName + " " this.lastName;
    }
}
var person = new Person("Mohammad""Nadeem");
console.log(person);
var person2 = new Person("Nagaraj""Mandalaparty");
console.log(person2);

 

 

 

As can be seen here both functions are not same.

person.fullName == person2.fullName
false
person.fullName === person2.fullName
false

Method in Prototype

Storing seperate instances of methods in each object may not be a good idea (memory wastage), and hence lets see what happens if we do the follows.

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;  
}
Person.prototype.fullName = function() {
    return this.firstName + " " this.lastName;
}
var nadeem = new Person("Mohammad""Nadeem");
console.log(nadeem);
var nagaraj= new Person("Nagaraj""Mandalaparty");
console.log(nagaraj);

As can be seen here both functions are same

nadeem.fullName == nagaraj.fullName
true
nadeem.fullName === nagaraj.fullName
true

Prototype Object of constructor function is shared among all the objects created using the same constructor function.

Further prototype forms the basis of Inheritance in JavaScript

JavaScript Object Properties and Methods

Private Property

function Person(name) {
        // private property, only available within this constructor function
        var type = "Human Being;
};

 

Privilege Method

function Person(name) {
        // private property, only available with this function constructor
        var type = "Human Being;
       // Privileged method accessing private properties and other privilege methods
       this.getType = function() {
            return type;
       };
};

 

Public Property And Method

function Person(name) {
        // public property
        this.name = name;
        // public method accessing public property
        this.getName = function() {
            return this.name;
        };
};
//OR
function Person(name) {
        // public property
        this.name = name;
};
// Pbulic method : the 'this' keyword refers to the object instance, you can access only 'privileged' and 'public' members
Person.prototype.getName = function() {
     return this.name;
};

Note : Always add public methods to prototype

 

Static Property And Method

//static Property : Shared by all instances of the class and stored in one place.
Person.db = "Oracle";
// Static method, can access static property
Person.find = function(id){ /*...*/ };

 

Private Method

function Foo(x) {
    //private property
    var y = 5;
    //private method
    var bar = function() {
        return y * x;
    };
    //public method
    this.public = function(z) {
        return bar() + x * z;
    };
}
var MYLIB = function() { 
    var aPrivateProperty = true;
    var aPrivateMethod = function() {
        // some code here...
    };
    return {
        aPublicMethod : function() {
            aPrivateMethod(); // okay
            // some code here...
        },
        aPublicProperty : true
    }; 
}();
var Person = function(){};
(function(){
  var findById = function(){ /* ... */ };
  Person.find = function(id){
    if (typeof id == "number")
      return findById(id);
  };
})();
   
Preferred
function Person() {
}
Person.prototype = (function() {
    var privateMethod = function() {
        // Private code here
    };
    return {
        // Person.prototype.constructor should be Person
        constructor:Person,
        publicMethod:function() {
            privateMethod ();
        }
    };
})();

Every object in JavaScript has a constructor property that references the constructor object that was used to create the instance of that object (refers back to the constructor function itself).

For instance, in all functions, the constructor property has a reference to the Function type constructor.
It is always a good idea to reset the constructor property of the prototype object after it has been completely replaced (in some cases), as follows:

ChildType.prototype.constructor = ChildType;

JavaScript Inheritance

JavaScript is a prototype-based language and hence it has the notions of a prototypical object (rather than make distinctions between classes and instances):

  • An object used as a template from which to get the initial properties for a new object.
  • Any object can be associated as a prototype of another object, sharing its properties.

Which forms the basis of inheritance in JavaScript.

In general, use constructor to inherit the instance properties and prototype chaining to to inherit methods and shared properties.

Simple Inheritance
var Animal = function(){
};
Animal.prototype.breath = function() {
  console.log('breath');
};
var Dog = function() {
  //Inherit instance properties
  //we have to call the parents constructor with the current instance, this is like `super()` in Java
  Animal.call(this);
};
//Inherit methods and shared properties
// Dog inherits from Animal
Dog.prototype = new Animal;
//OR
//Dog.prototype = Object.create(Animal.prototype);  // Copy the parent's prototype to the child's prototype
//Dog.prototype.constructor = Dog;   // Assign the constructor by assigning Class.prototype.constructor (because the parent's prototype was copied)
Dog.prototype.wag = function(){
  console.log('wag tail');
};
Calling Super
var BaseCar = function(config) {
    this.octaneRequired = 86;
    this.shiftTo = function(gear) {
        this.gear = gear;
    }
    this.shiftTo('park');
}
BaseCar.prototype = (function() {
     return {
        //It is always a good idea to reset the constructor property of the prototype object after it has been completely replaced
        constructor:BaseCar,
        engine : "I4",
        turbo : false,
        wheels : "basic",
        getEngine : function() {
            return this.engine;
        },
        drive : function () {
            console.log("Vrrrrrrrrrrm!");
        }
    };
})();
var PremimumCar = function() {
    BaseCar.call(this);
}
PremimumCar.prototype = new BaseCar;
PremimumCar.prototype.turbo = true;
PremimumCar.prototype.wheels = "premimum";
PremimumCar.prototype.drive = function() {
    this.shiftTo("drive");
    // Call Super
    BaseCar.prototype.drive.call(this);
}
PremimumCar.prototype.getEngine = function() {
    return "Turbo " this.engine;
}

Calling Super

SuperClass.prototype.method.call(this);

JavaScript Patterns

Immediately Invoked Function Expression (IIFE)

IIFE are the basis of module patterns and its variants.

Here are some examples

Simple Example
(function(){
  /* ... */
})();
Dependency
(function($, exports){
  exports.Foo = "wem";
})(jQuery, window);

Module Pattern

Modules are an integral piece of any robust application’s architecture and typically help in keeping the units of code for a project both cleanly separated and organized. As you build large applications, you will soon realize that it becomes increasingly difficult to keep the code base organized and modular. The module patterns help in keeping the code cleanly separated and organized.

As the variables and functions are contained in the module scope, we automatically prevent naming conflict with other scripts using the same names.

This pattern allows us to focus on which part of the code is exposed out of the class (public elements) and which parts of the code are hidden to the final user (private elements).

The Module Pattern must satisfy the following:

  • Private members live in the closure.
  • Public members are exposed in the return object.

The Module Pattern with Object Literal

It satisfies the following conditions, in addition to the original:

  • Private members are defined in the closure.
  • Public members are defined in the return object literal.
  • References to public members are via this, whenever possible.
var welcomeModule = (function(){
  return {
    name: "John",
    sayHello: function(){ console.log("Hello, " this.name + "!");}
    sayWelcome: function() { console.log( this.name + " Welcome to StackOverflow!");}
  }
})();

in order to make name and sayHello private, the references pointing to nameand sayHello in the various function body definitions also have to be changed.

The Module Pattern with Return Object Stub

It satisfies the following conditions, in addition to the original:

  • An empty return object stub is defined at the beginning.
  • Private members are defined in the closure.
  • Public members are defined as members of the stub
  • References to public members are via the stub object

you can see that public members are directly added to the stub object.

var welcomeModule = (function(){
  var stub = {};
  stub.name = "John";
  stub.sayHello = function(){ console.log("Hello, " + stub.name + "!");}
  stub.sayWelcome = function() { console.log( stub.name + " Welcome to StackOverflow!");}
  return stub;
})()

If you want to make name and sayHello private as before, the references to the now-private members have to be changed.

Revealing Module Pattern

It has a number of advantages over the other alternatives, such as

  • Rename public functions without changing function body.
  • Change members from public to private or vice versa by modifying a single line, without changing the function body.

The RMP satisfies three additional conditions in addition to those in the original:

  • All members, whether public or private, are defined in the closure.
  • The return object is an object literal with no function definitions. All right hand side expressions are closure variables
  • All references are via the closure variables, not the return object.
var welcomeModule = (function(){
  var name = "John";
  var hello = function(){ console.log("Hello, " + name + "!");}
  var welcome = function() { console.log( name + " Welcome to StackOverflow!");}
  return {
    name: name,
    sayHello: hello,
    sayWelcome: welcome
  }
})();

If you wanted to make name and sayHello private, you just need to comment out the appropriate lines in the return object.

In General RMP
var ModuleName = ModuleName || {};
ModuleName.CustomComponent = (function(dependency) {
  var somePrivateProperty = 1;
  var method1 = function() {
    dependency.methodFromDependency();
  };
  return {
    method1:method1,
    method2:method1
  }
})(dependency);

the methods are effectively namespaced inside ModuleName

Other Variations

In production code, however, you would want to use more a standardized approach to create modules. Currently, there are two main approaches to create modules.

  • CommonJS modules are usually more suited for server-side JavaScript environments such as Node.js.
  • Asynchronous Module Definition (AMD) : They are browser-first modules and opt for asynchronous behavior.

RequireJS

Know more

define(
  module_id /*optional*/,
  [dependencies] /*optional*/,
  definition function /*function for instantiating the module or object*/
);
//You can add a module without dependencies as follows:
define(
{
  add: function(x, y){
    return x + y;
  }
});
//The require module is used as follows:
require(["math","draw"], function ( math,draw ) {
  draw.2DRender(math.pi);
});

ES6 Modules

TODO

Namespaces

Namespaces are hierarchical containers for variables and functions. Their main goal is to organize names in order to avoid conflicts and redefinitions. This helps to avoid naming collisions between different parts of an application and other JavaScript libraries that are used, since we only need to keep all the identifiers unique under each different Namespace.

A good example of Namespacing is the mathematical functions and constants that JavaScript provides, which are grouped under the built-in JavaScript object called Math.

Modules avoid name conflicts and redefinitions as well, but they are mainly focused on functionalities; in fact, they provide mechanisms to export functionalities, to allow reuse of code, and to manage dependencies on other modules.

In JavaScript, the window object is also known as the Global Namespace, where each declared variable and function identifier is attached by default. A Namespace can be defined as a naming context where each identifier has to be unique. The main concept of Namespacing is to provide a way to logically group all the related pieces of a distinct and self-contained part of an application.

Designing an application architecture based on Modules and namespacing leads to better code organization and clearly separated parts. In such architectures, Modules are used to group together parts of the implementation that are related, while Namespaces connect them to each other to create the application structure.

js5

 

 

Refereces

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s