Prototype in Javascript

What is prototype in JavaScript?

An encapsulation of properties that an object links to. Simply put it allows you to share functions or properties with every single object of some specific type. Now every JavaScript object has a prototype. The prototype is also an object. All JavaScript objects inherit their properties and methods from their prototype.

There are two types of prototypes:

1. A function prototype is the object instance that will become the prototype for all objects created using this function as a constructor.
2. Where as an object prototype is the object instance from which the object is inherited.

Let us take an example:

function Employee(name)
{ 
  this.name = name;
}

Now the Employee.prototype is the function prototype. If I create an object of type Employee, then it has an object prototype, which is accessible as

employee.__proto__

Please note that the Employee.prototype is pointing to the same object as employee.__proto__.

var employee = new Employee(name);
Employee.prototype ===  employee.__proto__

Similarly, if I create an another employee object then also a new object is  pointing to the Employee.prototype object.

var employee1 = new Employee(name);
employee1.__proto__ === employee.__proto__  === Employee.prototype

It means that the prototype object is shared between objects of type Employee.

How the property is read by the javascript engine?

If I type employee.salary(), it will return an error that salary method does not exist. However, if I can modify the prototype object, so that the salary() function is attached with the Employee prototype then the function salary() will be available for every single object of type Employee.

Employee.prototype.salary = function () {return 0; };

Now employee.salary() will return 0. Which means that if the object does not have a property then javascript engine will check with __proto__ object.

You can check who owns the salary object with this line of code:

employee.__proto__.hasOwnProperty('salary')

It will return true because salary is assigned to Employee prototype.

How can I change prototype object?

If you assign something to the prototype variable, a new prototype object is created. However, any existing objects are still pointing to the old prototype. so far I have two variables, employee and employee1. Both of these variables are pointing to the same prototype. Which means that the employee.age and employee1.age will return the same type i.e. undefined. However, if I change the value of a prototype age of an Employee like this:

Employee.prototype = {age: 10}

Then employee.age == employee1.age are still same, pointing to the type undefined but employee.age != Employee.prototype.

When I create a new object of an Employee like this:

var employee2 = new Employee();

The employee2 is pointing to a new prototype and employee2.age will return 10.

How inheritance works?

  • Make a call to parent function by using <base function>.call(this, <parameters>).
  • Set prototype for derived class.
  • Set prototype.constructor for derived class.
'use strict'
 
 function Employee(name){
 this.name = name
 }
 
Employee.prototype.age = 5; 
Employee.prototype.calculateSalary = function() { return 1000 };

function Manager(name) {
 // if you are not going to call the base constructor then
 // you are not going to have a name.
 Employee.call(this, name) // 1 
 this.hasCar = false;
}
 
Manager.prototype = Object.create(Employee.prototype); // 2.
Manager.prototype.constructor = Manager; //3.
 
var manager = new Manager('test');

console.log(manager.calculateSalary());

 How Prototyping is done with Classes?

'use strict'
 
 class Employee {
 constructor(name) {
 this.name = name;
 } 
 
 calculateSalary() {
 return 1000;
 }
 }
 
 class Manager extends Employee { 
 
 constructor(name, hasCar) {
 super(name);
 this.hasCar = hasCar;
 } 
 }

var manager = new Manager('test', true);
 console.log(manager.calculateSalary());

 

 

 

Playground – Javascript Object Properties.

How to define properties?

There are many ways to do this:

1. Assign a Json object aka bracket notations.

var employee = {
 name : {first: 'Vinod', last: 'Kumar'},
 gender: 'M'
};

2. Use . operator

var employee.fullName = "Amit Malhtora";

3. Use [] operator

var employee["fullName"] = "Amit Malhotra";

4. Use ECMAScript 5 defineProperty with accessor (get; set;) descriptor

Object.defineProperty(employee, 'fullName',
 {
 get: function() {
 return this.name.first + ' ' + this.name.last;
 },
 set: function (value){
 var nameParts = value.split(' ');
 this.name.first = nameParts[0];
 this.name.last = nameParts[1];
 }
});
 
employee.fullName = 'Amit Malhotra'
 
console.log(employee.name.first); // OUT: Amit

5. Use ECMAScript 5 defineProperty with property descriptor

Object.defineProperty(employee, 'fullName', {
 value: 'Amit Malhotra',
 writable: true,
 enumerable: true,
 configurable: true
});

What is Property Descriptor after all?

In JavaScript, you can define a metadata about the property. The following descriptor can be defined as writable, configurable and enumerable.

You can get the property descriptor using Object.getOwnPropertyDescriptor method.

Object.getOwnPropertyDescriptor(employee.name,'first');
 
// Out: Object
 
/* {
value: Amit
writable: true
enumerable: true
configurable: true
} */

writable – allow to change.

Object.defineProperty(employee, 'age', {writable: false});

Now if I try changing property as:

employee.age = 12

Then will throw this error:

TypeError: Cannot assign to read only property 'age' of 
object '#<Object>, Please note that it will throw an 
exception only if we use 'use strict'. Otherwise it will 
silently fail without changing the value of age to 12.

enumerable – allow to enum your property like this:

for(var propertyname in employee){
 display(propertyname + ': ' + employee[propertyname])
}

It returns name: [object Object], gender: M

If you set the enumerable to false:

Object.defineProperty(employee, 'gender', 
{enumerable: false})

 

The Object.keys(employee) will not return gender property. 
Similarly, if the Object.defineProperty(employee, 'gender',
{enumerable: true}) then it will return gender. You can 
still access gender like employee.gender, but you cannot 
see in Object.keys(employee)

configurable – That you can change some property descriptor

Object.defineProperty(employee,'age', {configurable: false})

Now you cannot change the property descriptor enumerable, configurable, or delete age. However, you can change writable.

 

Debug Postman

Recently, I came across a situation when I wanted to see the result of console.log written as a part of Postman script.

I could not see any outgoing call or console logs in a console of my chrome.

After a bit of research it is understood that there is a separate way of opening a console screen of a chrome app package.

To enable this feature you need to type chrome://flags/#debug-packed-apps in the URL bar in your Chrome browser window:

Once it is enabled, restart your chrome. Now you can right click on the Postman app, and inspect.

Tada! You can now view console logs and any network calls going out of the Postman.

Demystifying NodeJs “exports” keyword

Introduction

There has been a little confusion, in my mind, about using module.exports or exports in my nodejs coding. I have seen some code on github or otherwise, many of us are using the following exports statements:

  • exports.fn = function() { … }
  • module.exports.fn = function() ( … )
  • module.exports = exports = myobject.

Then my mind wonder:

  • What is the difference between “module.exports” and “exports” ?
  • Why Nodejs has introduced module.exports as well as exports ?
  • What does it means by module.exports = exports = object ?
  • What I prefer?

In this post, I will try to answer the above four questions. First, we will give a practical sense to exports.fn, module.exports.fn & module.exports = exports statement.

So let us start our journey with codebased

Explanation

Simplified Version

The “exports” is simply a global reference to module.exports, which initially is defined as an empty object that you can add properties to. Thus, exports.fn is shorthand for module.exports.fn.

As a result, if “exports” is set to anything else, it breaks the reference between module.exports and “exports”. Because module.exports is what really gets exported, “exports” will no longer work as expected. Thus, to ensure it is referencing to the same memory location, many of us reassign the value to module.exports as well as exports at the same time.

module.exports = exports = myobject

Detailed Version

In this sesion, I will try to demonstrate the same with code.

I pre-assumed that your nodejs is available through the command prompt. If you need an installation help, please click here.

Let us create a new file in node.

-------- laptop.js -----------
 
 exports.start = function(who) {
  console.log(who + ' instance has started this laptop');
 }

// calling a method within laptop.js
module.exports.start('module.exports');

Now create a new file that will import laptop file.

-------- app.js -----------
 
 require('./laptop.js')

Call app.js from the command prompt.

c:\ node app.js

Output
-----------------------------------------------

module.exports instance has started this laptop.

As you can see that even though we have defined a function with “exports” variable, it is available through “module.exports”.

Similarly if you do it opposite that will work too.

-------- laptop.js -----------
 
 module.exports.start = function(who) {
  console.log(who + ' instance has started this laptop');
 }

exports.start('exports');

Call app.js from the command prompt.

c:\ node app.js

Output
-----------------------------------------------

exports instance has started this laptop.

Now let see what happens here:

-------- laptop.js -----------
module.exports.start = function(who) {
 console.log(who + ' instance has started this laptop');
 }
 exports.start = function(who) {
 console.log(who + ' instance has started this laptop');
 }

exports.start('exports');
module.exports.start('module.exports');

Any guess what will be outcome?

Yes, the module.exports.start has overridden by the export.start.

Call app.js from the command prompt.

c:\ node app.js
 Output
 -----------------------------------------------

 exports instance has started this laptop.
 exports instance has started this laptop.

It is clear that “exports” is an alias to “module.exports”.

We will now try to recall our  questions one by one and answer those:

1. What is the difference between exports vs module.exports ?

Node.js does not allow you to override “exports” variable with any another memory address. However you can attach N number of properties to “exports”. Thus anything that assign directly to “exports” will not be available when it is exported.

You can export anything through “module.exports” but not with”exports” keyword.

You can do this:

module.exports = function() {
 }

or

module.exports = myobject;

Basically, anything that you have exported through module.exports will be available at app.js above. However, you cannot do like this in your laptop.js and then consider it is available in app.js.

exports = function () {
 }

or

exports = myobject;

It is clear now that you can export anything (function, object, constant value) through “module.exports” but not with “exports”.

Sounds crazy? Yes it is.

2. Why they have introduced module.exports as well as exports ?

I think the main reason could be to reduce number of characters to type?

3. What does it means by module.exports = exports = object ?

Many of us set module.exports and exports at the same time, to ensure exports isn’t referencing the prior exported object. By setting both you use exports as a shorthand and avoid potential bugs later on down the road (within same file).

Here is a piece of code to make it:

------ laptop.js ------

exports = "exports";
module.exports = "module.exports";

console.log(exports);
console.log(module.exports);

Call app.js from the command prompt.

c:\ node app.js
 Output
 -----------------------------------------------
exports
module.exports

Because they are pointing to a different location and by any chance the module has decided to use “exports” (not “module.exports” variable) value after it is set it will not be in sync.

Thus, to make it in sync. it is advisable that the “exports” variable has been set by anything you would want to define a rule that whenever we set module.exports with any value set the same value to exports in the same line.

Here is an example:

------ laptop.js ------
 
exports = 'i am value ';
module.exports = exports = function() {
   console.log('function is called.');
 }
console.log(typeof exports)
-------- app.js --------

var laptop = require('./lib/laptop.js');
laptop();

 

Call app.js from the command prompt.

c:\ node app.js
 Output
 -----------------------------------------------
function
function is called.

You can see in the output that because “exports” as well as “module.exports” are set to a function the output of “typeof” statement is “function”. If you don’t assign a function to exports then the typeof statement will produce “string”.

Thus, to remove any potential bugs we decide to set exports as well as “module.exports” at the same time.

Now this discussion is coming to an end with the last question i.e.

What I prefer?

Personally, I prefer to export a constructor function that can be used create an instance of a module.

example:

------ laptop.js ------

var laptop = function() {}
laptop.prototype.start = function() {};
laptop.prototype.stop = function() {};
laptop.prototype.suspend = function() {};
module.exports = exports = laptop;
 ------ app.js ------
var laptop = require('./laptop')
var mac = new laptop();
var win = new laptop();

However, if I want to give a singleton object then I replace the following line in laptop.js

------ laptop.js ------

module.exports = exports = new laptop();

and in app.js

 ------ app.js ------

var mac = require('./laptop');
mac.start();

Conclusion

  • We understand now that the exports is an alias to module.exports that can shorthand your writing in module development.
  • It is recommended that we point exports alias to module.exports value. Thus you should set exports whenever you are setting module.exports.
  • Since my background is .net, I recommend to export a class (constructor function) or an object.

– Happy coding!

How to create jquery Plugin?

Idea behind this plugin is to catch any event on <a> link and open the URL on new screen.

/*! jQuery anchormaaster Plugin – v1.0 – 18/2/2014
* Copyright CM (c) 2014 codebased@hotmail.com; Licensed MIT */

(function ($) {

// function that go through each link available in the given html object/
// and connect click event for opening a link to the new window.
$.fn.linkExtender = function (options) {

// default settings are merged with options parameter.
var settings = $.extend({
channelmode: 0,
fullscreen: 0,
height: 600,
left: 50,
location: 0,
menubar: 0,
resizable: 1,
scrollbars: 0,
status: 1,
titlebar: 1,
toolbar: 1,
top: 100,
width: 800
}, options || {});

var winprop = JSON.stringify(settings).replace(/}|{|”/g, ”).replace(/:/g, “=”);

// loop through all a link that has been within
return this.find(“a”).each(function () {

$(this).click(function () {

// it did not worked as expected by sending settings object.
// window.open($(this).attr(‘href’), “anchormasterwinpop”, settings);
// hence I’d to use winprop – string based value.
window.open($(this).attr(‘href’), “anchormasterwinpop”, winprop);

// STOP THE CLICK BUBLE!!!
return false;
});
});
};
})(jQuery);

How to Extend string object in JavaScript?

$(function () {

// — DOM is ready to action on.

/*
Summary: startsWith should take a single argument and return true if the provided string is a
prefix of this.
*/

if (typeof String.prototype.startsWith !== ‘function’) {

// checked and there is no startsWith (pre-defined) method.
String.prototype.startsWith = function (prefix) {
return this.indexOf(prefix) == 0;
};
} else {

// raise the log message for the developer.
raiseLog(“startsWith prototype is already defined. Unable to attach StringExtensinos.js.startsWith”);
}

/*
Summary: endsWith should take a single argument and return true if the provided string is a
postfix of this.
*/

if (typeof String.prototype.endsWith !== ‘function’) {

// checked and there is no endsWith (pre-defined) method.
String.prototype.endsWith = function (postfix) {
return this.indexOf(postfix, this.length – postfix.length) !== -1;
};
} else {

// raise the log message for the developer.
raiseLog(“endsWith prototype is already defined. Unable to attach StringExtensinos.js.endsWith”);
}

/*
Summary: This method should remove all html/xml tags from this.
*/

if (typeof String.prototype.stripHtml !== ‘function’) {
// checked and there is o stripHtml (pre-defined) method.
String.prototype.stripHtml = function () {
// By wrapping around p tag we have made
// sure that it is actually a valid html.
return jQuery(‘<p>’ + this + ‘</p>’).text();
};
} else {

// raise the log message for the developer.
raiseLog(“stripHtml prototype is already defined. Unable to attach StringExtensinos.js.stripHtml”);
}

// raise the log to the console. This tool is handy for Mr. developer – F12
function raiseLog(message) {

// ensure that we have a console function available.
// later we may move this object into more jquery form and add a plugin.
if (typeof console == “object” && typeof console.log == ‘function’) {
console.log(message);
}
}
});