Javascript

Javascript Constructor Functions and The “this” Keyword

Javascript Constructor Functions and The this Keyword

You may have heard before about constructors in object oriented languages such as C++ and Java. The same concept also exist in javascript but with a different methodology.

 

 

Constructors are usually used in the creation of objects. In languages such as C++ in order to create objects you have to create a user defined class. However in javascript to create an object you have to create a constructor function. Note that in Ecmascript 6 there is a modern way of creating objects using classes but it’s not fully supported yet a cross web browsers, so in this article we will talk about constructor functions.

A constructor function is a simple javascript function that is used to create objects using the “new” keyword. So instead of calling the function directly you have to invoke it with “new” keyword. 

Consider this example:

function Rectangle()
{
    this.width = 70;
    this.height = 40;

    console.log("new object created!");
}

Now to create an object from Rectangle  we have to use the new keyword:

var rectangle = new Rectangle();
console.log(rectangle);

Now check the console you will see this output:

new object created
Object { width: 30, height: 40 }   // object

As you see in the output that the rectangle type is an object not Function. Also you can view the object constructor using javascript constructor property like so:

console.log(rectangle.constructor);

// output
function Rectangle()

But how this is works? The secret behind that is the “this” keyword in the above function. “this” is a special keyword in javascript like var, let, const etc. “this” refers to the current object when a new object is created. So “this” is useless until a new object instantiated.

So in the above example when i create a new object like this:

var rectangle = new Rectangle();

Now “this” refers to the rectangle object, therefore using rectangle object i can access any property inside the function like so:

console.log(rectangle.width);
console.log(rectangle.height);

 

Another advantage of constructor functions is that you can create as many objects as you can, each object has it’s own state:

var rectangle2 = new Rectangle();
rectangle2.width = 50;
rectangle2.height = 20;
console.log(rectangle2.width, rectangle2.height);
        
var rectangle3 = new Rectangle();
rectangle3.width = 200;
rectangle3.height = 80;
console.log(rectangle3.width, rectangle3.height);

 

Constructor Function Parameters

As with normal javascript functions you can pass parameters to constructors as well, so modify the above example to pass the width and height of rectangle:

function Rectangle(width, height) 
{ 
    this.width = width; 
    this.height = height; 
             
    console.log("new object created"); 
}
        
let rectangle1 = new Rectangle(70, 20);
console.log("Rectangle 1: " , rectangle1.width, rectangle1.height);
        
let rectangle2 = new Rectangle(300, 50);
console.log("Rectangle 2: " , rectangle2.width, rectangle2.height);
// output
new object created
Rectangle 1:  70 20
new object created
Rectangle 2:  300 50

Also you can pass a parameter that’s is also a parameter created from a constructor function.

For example in the above example if we want to add another argument that specify the rectangle style like background, border type, etc, we can make another constructor function like this one:

function RectStyle(background, borderStyle)
{
    this.background = background;
    this.borderStyle = borderStyle;
}

Then create a new object from this function:

var rectangleStyle = new RectStyle("red", "dashed");

Then pass this argument as a third argument to Rectangle:

function Rectangle(width, height, rectStyle) 
{ 
     this.width = width; 
     this.height = height; 
     this.rectStyle = rectStyle;
     console.log("new object created");  		 
}

Now when creating a new instance of Rectangle pass the third argument “rectangleStyle” as shown:

let rectangle1 = new Rectangle(70, 20, rectangleStyle);

As this point you can access any rectangle style property from rectangle1:

console.log(rectangle1.rectStyle);
console.log(rectangle1.rectStyle.background);   // red
console.log(rectangle1.rectStyle.borderStyle);   // dashed

 

Built in Constructors In Javascript

Javascript have many built-in constructor functions for each primitive types like String, Number, Boolean, Object, etc.

For example you can declare a string like this:

const str = new String("hello world");

console.log(str);   // Object String {'hello'}

Also you can declare numbers:

const num = new Number(200.56);
        
console.log(num);  // Number {200.56}

But be careful don’t use this approach as it slows down the program, instead use the primitive types directly.

 

Declaring Methods Inside Constructors

Like declaring properties inside constructor functions we can declare methods also, using the “this” keyword and those methods is accessible outside when a new object is created.

Imagine in the above example that we want to add a method to draw the rectangle on the browser window:

<canvas width="600" height="600" id="my_canvas"></canvas>

    <script>

        function Rectangle(x, y, width, height, color) 
        { 
             this.width = width; 
             this.height = height; 
             
             this.draw = function () {
                var canvas = document.getElementById('my_canvas');
                if (canvas.getContext) {
                    var ctx = canvas.getContext('2d');
                    ctx.fillStyle = color;
                    ctx.clearRect(x, y, width, height);
                    ctx.fillRect(x, y, width, height);
                }
             } 
        }
        
        let rectangle1 = new Rectangle(30, 50, 150, 50, 'green');
        rectangle1.draw();
        
        let rectangle2 = new Rectangle(300, 200, 300, 50, 'red');
        rectangle2.draw();
    </script>

Here i have added the draw() method which draw rectangle using Javascript canvas api. Then i declared two instances of the Rectangle, and passing different parameters for x,y, width, height, and color. Finally calling draw on each object.

 

In addition to that we can also add properties and methods to already created objects to add new functionality to that object. For example let’s add a method to calculate the area of rectangle:

rectangle1.getArea = function() {
    return this.width * this.height;
}
        
console.log(rectangle1.getArea());

// output
7500

However this method is only available on rectangle1 only not shared across any Rectangle object.

So any attempt to invoke getArea() on rectangle2 you will get an error:

console.log(rectangle2.getArea());   // Uncaught TypeError: rectangle2.getArea is not a function

This is some of the advantages of constructors is that as i mentioned above every object has it’s own state. But if you need that the getArea() method to be available globally on every instance, there is a way using the object prototype. 

 

Object Prototypes

According to MDN prototypes are the mechanism by which JavaScript objects inherit features from one another. Every object in javascript has it’s own prototype which enable us to modify that object to add certain properties and methods.

You can get the prototype of any object using Object.getPrototypeOf() method like so:

console.log(Object.getPrototypeOf(rectangle1));

If you run this you will see something similar to this output:

{constructor: ƒ}
   constructor: ƒ Rectangle(x, y, width, height, color)
   ....
   ....

The object prototype displays the structure of the object which consists of the function argument, caller, length, name, and other info like toString(), valueof.

Using the object prototype we can easily add methods and properties to an existing object which will be available globally across all instances of that object.

So let’s modify the getArea() method to be accessible to every instance of Rectangle:

Rectangle.prototype.getArea = function() {
    return this.width * this.height;
}
        
console.log("Rectangle 1 area: ", rectangle1.getArea());
                
console.log("Rectangle 2 area: ", rectangle2.getArea());

output:

Rectangle 1 area:  7500
Rectangle 2 area:  15000

Also we can add properties:

Rectangle.prototype.shapeType = "Rectangle";

console.log(rectangle1.shapeType);

// output
Rectangle

 

In the same way you can modify existing Javascript constructors like String, Number, etc. For example imagine you want to add a method to capitalize every word in string. We can add this method as follows in the String prototype:

String.prototype.capitalize = function() {
    return this.toLowerCase().replace(/\b[a-z]/g, function(a) {
            return a.toUpperCase();
      });
}
        
const str = "hello world";
console.log(str.capitalize());  // Hello World

 

Freezing Objects

You can prevent an object from being modified either to not allow adding properties or methods or not to modify the object prototype by using Object.freeze(obj) method. This method accept either a literal object or an object created with a constructor function.

Let’s modify our previous example and call Object.freeze() on rectangle1, then modify the shapeType property:

Object.freeze(rectangle1);
        
rectangle1.shapeType = "Square";
        
console.log(rectangle1.shapeType);

If you run this example you will see that the shapeType is still Rectangle not Square, and this is the intended behavior of Object.freeze(). In strict mode this example will trigger an error like this:

Uncaught TypeError: Cannot add property shapeType, object is not extensible

Also you can’t add new methods to frozen objects:

Object.freeze(rectangle1);

rectangle1.printWidth = function() {
    console.log("My width", this.width);
}
        
console.log(rectangle1.printWidth());     // Uncaught TypeError: rectangle1.printWidth is not a function
    

To detect that an object is frozen or not we can use Object.isFrozen(obj) method:

console.log(Object.isFrozen(rectangle1)); // true

Some benefits from freezing objects when you intend to build a third party package or library and you don’t want users to modify the internal implementation of the library.

 

Checking For Object Properties

To check the existence for specific property in an object there is many ways. The first we can use hasOwnProperty() method. But this method return true if this property is a direct in the object.

For example:

console.log(rectangle1.hasOwnProperty('width'));  // true

Or more better syntax:

console.log(Object.prototype.hasOwnProperty.call(rectangle1, 'width'));  // true

For inherited properties false is returned

console.log(rectangle1.hasOwnProperty('toString'));  // false

To check for direct and inherited properties the “in” operator can be used:

console.log("width" in rectangle1);     // true
console.log("toString" in rectangle1);  // true

To get the list of all properties of an object we can either of these methods:

  • Iterate the object with for..in
for(var i in rectangle1) {
     console.log(i + ' -> ' + rectangle1[i]);
}
  • Using getOwnPropertyNames() method:
Object.getOwnPropertyNames(rectangle1).forEach(function (val) {
           console.log(val + ' -> ' + rectangle1[val]);
 });

Note that the later method using getOwnPropertyName() doesn’t return the properties defined after the object is created like shapeType while the first method return all the properties.

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments