Introduction
This article is a brief guide on how to create objects in different ways, implement inheritance and encapsulation, use the prototype property, and test my code by using the unit test framework for JavaScript QUnit (http://qunitjs.com/).
Background
Factory Pattern: The factory method pattern is an object-oriented creational design pattern to implement the concept of factories and deals with the problem of creating objects (products) without specifying the exact class of object that will be created. - From Wikipedia.
Basically, it is a specific way to create new object instances by using a method.
Everything is a Object
In JavaScript, everything is an object, keep it present always.
JavaScript is a very flexible language which could be an advantage or a disadvantage, if you are a ordered developer then you will be fine. You can create objects but the relationship between them and object-oriented programming is not direct. For example, there is no class
keyword in JavaScript, but you can simulate similar functionality and OO concepts like encapsulation and inheritance.
JavaScript is called a prototype-based, object-oriented programming language, so you will use prototypes to create or clone objects before using them.
QUnit
I will use Qunit to create test methods and assert values:
Download QUnit .js and .css files from http://qunitjs.com. Add both to your project. Read getting started section. We will use the equal
function which basically compares two values and evaluates them as a Boolean condition.
Object Literal Pattern
The easiest way to create an object, just need name, curly braces and specify the properties and/or methods you need:
var person = {
name: 'steve',
age: 25,
getInfo: function () {
return this.name + ' ' + this.age;
}
};
Here, I created a person
object with two properties; name
as string
and age
as number; also, a function with name getInfo
that returns a string
with the value of both properties.
Test Method
On this test method, I use the person
object already created and invoke its getInfo()
function.
test("Object literal test", function () {
expect(1);
var expected = 'steve 25';
var actual = person.getInfo();
equal(actual, expected, actual);
});
After running the page, the result is:
This indicates that the 'Object Literal Test' test passed without errors.
Factory Pattern
Every object in JavaScript has a prototype object which can be used to clone an object by using the new
keyword.
function getEmployee(name, department) {
var newEmployee = new Object();
newEmployee.name = name;
newEmployee.department = department;
newEmployee.getInfo = function () {
return this.name + ' ' + this.department;
}
return newEmployee;
};
First, I need to create a function which allows the factory pattern implementation, receiving by parameters the values of the properties I need to set, inside the function use the New Object()
instruction to create an empty object, finally just specify the properties and methods needed.
Test Method
In this test, I create two object instances named employee1
and employee2
, both with a name
and department
.
test("Factory Pattern test", function () {
expect(2);
var employee1 = getEmployee('David', 'financial');
var employee2 = getEmployee('Mark', 'sales');
equal(employee1.getInfo(), 'David financial', employee1.getInfo());
equal(employee2.getInfo(), 'Mark sales', employee2.getInfo());
});
Result:
Class Simulation
As I said, there is no class
keyword in JavaScript; instead, we can simulate it using a function and a default constructor.
function Computer(brand, is64, color) {
var _brand = brand;
var _is64 = is64;
var _color = color;
this.getInfo = function () {
return _brand + ' ' + is64 + ' ' + _color;
}
};
Here, I created a function that works as a default constructor and at the same time, allows me to implement encapsulation. Using the var
keyword to declare each property (or variable) ensures that they cannot be modified by external code.
Test Method
Just create two objects of type computer
and assign their internal values by using the default constructor.
test("Class simulation", function () {
expect(2);
var toshiba = new Computer('toshiba', true, 'black');
var hp = new Computer('hp', false, 'red');
equal(toshiba.getInfo(), 'toshiba true black', toshiba.getInfo());
equal(hp.getInfo(), 'hp false red', hp.getInfo());
});
Result:
Prototype Property
Everything is an object in JavaScript, and everything has a prototype property which is an object itself that contains properties and methods that should be available to all instances of the type you are working with.
For this example, we will rewrite the getInfo
method for the Computer
class using its prototype
property. I will name it Computer2
class.
function Computer2(brand, is64, color) {
this.brand = brand;
this.is64 = is64;
this.color = color;
};
Computer2.prototype.getInfo = function () {
return this.brand + ' ' + this.is64 + ' ' + this.color;
};
The difference is on getInfo
implementation, it is made outside the definition of the class and using the prototype property so I’m affecting all the instances of the computer2
object that use the function getInfo
.
Test Method
test("Instance test using prototype, overwrite original function shared across all instances",
function () {
expect(2);
var toshiba = new Computer2('toshiba', true, 'black');
var hp = new Computer2('hp', false, 'red');
Computer2.prototype.getInfo = function () {
return this.brand + ' is ' + this.is64 + ' and of color ' + this.color;
};
equal(toshiba.getInfo(), 'toshiba is true and of color black', toshiba.getInfo());
equal(hp.getInfo(), 'hp is false and of color red', hp.getInfo());
});
After creating the two instances of Computer2
, I overwrite the getInfo
function with a new implementation which basically changes the return text. The interesting point here is that I’m changing the implementation for all the instances, for created ones and the new ones.
Result:
Inheritance
To implement inheritance in JavaScript, we have to use something called IIFE (an immediately-invoked function expression (or IIFE, pronounced "iffy") is a JavaScript design pattern which produces a lexical scope using JavaScript's function scoping, - Wikipedia.org), basically, a block of code that is invoked immediately after the browser loads.
So let’s create three classes, a superclass and two subclasses, as follows:
Next is my superclass called USER
, it has two properties and a method:
var User = (function () {
function User(name, isActive) {
this.name = name;
this.isActive = isActive;
}
User.prototype.getInfo = function () {
return this.name + ' is active: ' + this.isActive;
}
return User;
})();
Next is the subclass Developer
, there are several important parts:
In the inline function used to create the object, I receive parent
, which represents the superclass I’m inheriting. Use the prototype
property to change the object type to User
. Use parent.call
to make a reference to the parent
function (constructor) and send this to be assigned as a child. Write the new methods as needed, for example: Writecode()
. At the end of the IIFE declaration, specify the parent
class between parentheses, like this: (user)
.
var Developer = (function (parent) {
Developer.prototype = new User();
Developer.prototype.constructor = Developer;
function Developer(name, isActive, languajes) {
this.languajes = languajes;
parent.call(this, name, isActive);
}
Developer.prototype.WriteCode = function () {
return 'writing code!';
};
return Developer;
})(User);
var Dba = (function (parent) {
Dba.prototype = new User();
Dba.prototype.constructor = Dba;
function Dba(name, isActive, isSqlDba, isOracleDba) {
this.IsSqlDba = isSqlDba;
this.IsOracleDba = isOracleDba;
parent.call(this, name, isActive);
}
Dba.prototype.MakeBackup = function () {
return 'backup done!';
};
return Dba;
})(User);
Test Method
Basically, create two different child objects instances; invoke the parent method (getInfo
) as well as the children's new methods (WriteCode
and MakeBackup
):
test("Inheritance Test", function () {
expect(4);
var dev = new Developer('James', true, ' vb.net and c#');
var dba = new Dba('John', true, true, false);
equal(dev.getInfo(), 'James is active: true');
equal(dba.getInfo(), 'John is active: true');
equal(dev.WriteCode(), 'writing code!', dev.WriteCode());
equal(dba.MakeBackup(), 'backup done!', dba.MakeBackup());
});
Using the Code
Check the link below for a Visual Studio 2013 solution with all the code I used inside the article. Uncomment specific tests to see the results:
History