1.0 Object Oriented Programming
JavaScript was not at all intended to be an Object Oriented Programming Language. At the time of its creation there were already other languages present which were doing this task, namely C++ was the modified version of C with Classes and other object oriented features. Another language which took the grounds was Java which was basically designed to serve the concept revolving around Object Oriented Programming and to overcome the shortcomings present in C++.
JavaScript was not introduced for such a programming concept yet the designer was aware of the paradigm shift, which was moving from procedural programming to Object oriented programming. Therefore to say that it was an Object Oriented Programming Language would be completely unfair. No Programmer who knew C++ and Java or any other language like small-talk would agree that JavaScript was not meant to be Object Oriented. However, it had the facilities provided by the designer to have some features of Object Oriented Languages. For example to share the code from other object JavaScript use prototypal inheritance as opposed to class inheritance. Similarly JavaScript also provided features of functional programming such as treating functions as values and passed around to other functions which is only found in functional language. Thus to summarise, JavaScript is a prototypal based functional language which has evolved in last two decades.
1.1 Objects Data Type
An individual piece of data is usually stored in a variable of some type but when you have number of variables which relates to a single entity then they are usually stored in some sort of structure so they can be more easily defined, maintained and manipulated while having interaction with other units. JavaScript way of grouping related variables in a self contained unit is to store each of them in key/name and its value pair, known as properties of the object and their values. This technique of storing variables is known as associative arrays, dictionary or hash tables. Since the key is stored as a string , It basically provides a mapping between key {string} to value thus also known as map.
One of the uses of objects is to organize self contained unit possessing some properties and providing some methods. Before ECMAScript-6 there was no concept of classes in JavaScript and inheritance was implemented through a special property __proto__ called Prototype. But with ECMAScript-6 class syntax is introduced to help programmers coming from class based object oriented language. This introduction is only regarded as synthetic sugar coated technique, what does it mean is that internal system is same as before.
2.0 Creating JavaScript Objects
- In JavaScript there are different ways to create an object which way you choose depends upon its use. Some of common ways of creating the object are mentioned below followed by their examples.
- Using literals
var obj = { }// ECMAScript-3 - Using Object constructor
var obj = new Object()// ECMAScrip-3 - Using Constructor function
var obj = new <function name> - Using
Object.create(prototype)from a given prototype // ECMAScript-5 - Using classes and instantiating the object
class <identifier>{ .....}// ECMAScript-6
2.1 Creating Objects with Literal { }
- The easiest and preferred way of creating an object is to create it with curly brackets known as
Literal notation.
1var obj = {} //an empty object
- A name does not have to be generic, it can be descriptive so that it makes us easy to comprehend.
1var obj = {}
- In above case, JS provides a quick way of creating an object which is created internally using the special function called constructor function. it does not have any state as no members exist yet. But properties and methods can be added later on when needed. This way of adding properties is regraded as expando properties and regarded as extending the object.
2.2 Properties of Objects
Until ECMAScript-5 there has been two ways to define properties of objects but ECMAScript-5 introduced a new way to define the property with more control over them;
At the time of object creation,
var myObject = {x: 10 , y: 20}.Assign properties to object by extending the object, known as
expando property,mObject.z = 30Use ECMAScript-5 provided built in methods
Object.defineProperty({obj,prop,itsValue})for a single property or for more than one useObject.defineProperties(obj......).The first way is to define the properties at the time of object creation. So when an object is created they already have he properties of the object The second way is to add properties to the object after the object has been created. This is a very useful which allows you to add more properties on the fly to any object and delete them when not needed. These properties are also known as
expando properties and done by extending the object.Prior to ECMAScript-5, properties had only one attribute, that is every property had its value but ECMAScript-5 added other attributes using the
property descriptor object.
2.3 What is JS property descriptor
- A property descriptor is another object that holds information about the properties, it is sort of meta data object. It can be of two types either
Data DescriptororAccessor Descriptor. In JS it is also a separate object created whenever an object gets created to keep track of new object’s properties. It can be accessed usingObject.getOwnPropertyDescriptor(obj)function. Data Descriptor deals with the four properties of the descriptor object{value: "",writable:"",enumerable:"",configurable:""}while Accessor Descriptor deals withgetorsetor with both of them.
2.4 Properties’ attributes
- Property attributes can be set at the time of creating properties but if not created explicitly, they get default values assigned to them. Let’s see what are those default values;
1var x
2Object.getOwnPropertyDescriptor(global, 'x')
3/*{ value: undefined, writable: true, enumerable: true, configurable: false }*/
Value Its value assigned when you declared a variable, if not it gets the default value of
undefined.Writable means that the old value can be deleted and new values can be assigned by default it is assigned
truethus can be updated.Enumerable:As the name indicates that if set to true the variable can be accessed using enumeration like
for..inloop or usingobject.keys. And can be saved permanently usingJSON.stringifymethod. By default it is assignedtrue. In case of beingfalsethis property is not enumerated.Configurable:To control the above two attributes behaviour i.e., whether the above two can be set to other values or not. If allowed that is
configurable = true, they can be set to eithertrueorfalse. But ifconfigurable = falsethe above two can not be changed. Their attributes remains as it is as the time of creation and the property can not be deleted.
2.5 Adding Properties to Object
In real life, objects have properties and behaviours, they do not exist without them. In JS, one can create objects with the associated properties or may add them later on as needed and delete them when not needed.
1var obj = {}
2obj.fname = 'Jack' //adding properties using . dot notation
3obj.fname = 'Jill' //it can be updated, it is not a constant
4console.log(obj.fname) // Jill. accessing properties using dot(.)
5console.log(obj['fname']) // Jill. using square brackets []
6delete obj.fname //deleting properties
7/*Note: you can not delete inherited properties. Every object when created inherit
8 some properties automatically*/
9console.log(obj.fname) //undefined
2.6 Object Properties can be accessed in two ways
To access object properties javaScript provides two ways, either use dot notation . or use square brackets notation[]. Therefore console.log(obj.fname) and console.log(obj['fname']) will produce the same result. When using square brackets notation an expression can be used to access object’s property, provided expression must yield to a property name. For example, if var alias = "fname" then console.log(obj[alias]) will provide same result. Just like other variables behaviour, if a property is not defined, accessing it will return an undefined. And if an attempt is made to get the value of an undefined the compiler will throw TypeError.
1.2.7 Creating Object with defined properties
- It is not necessary that you first create an empty object and then start adding properties to it. Objects can be created with their existing properties.
1var point = {
2 x: 10,
3 y: 20,
4 draw: function (dx, dy) {
5 console.log('Drawn')
6 }
7}
1.2.8 Why to use square bracket notation
- It is either used to access or set properties. If you want to use any reserved words as a name of your property or use any special characters or spaces between the property name or any numerical value then you will have to use square brackets notation to access it and enclosed it with quotes, instead of dot notation otherwise it will be flagged as an error. Similarly there will be times when accessing properties dynamically using dot operator would not be possible but square bracket would be used instead.
Another place where you would use the square bracket notation instead of dot is when you do not know the property before hand. This happens often when dealing with web pages and making changes dynamically.
1//var point = { x: 10, y: 20, z axis: 0} // error b/c of space,
2var point = { x: 10, y: 20, 'z axis': 0, '!': 'Exclamation' } // correct
3// To access the properties enclosed with quotes, you can not use dot (.)
4//console.log(point.!);//error
5console.log(point['!']) // Exclamation. o.k
6console.log(point.time) //time is not defined
7console.log(point.time.show) // can not read property of undefined.
8/* TypeError: The above line comes out as a type error, and very common specially in dynamic environment where one tries to invoke some service on an object which does not exist. In the above example the `time` never existed but error is thrown not when it was accessed but when a service is invoked upon it.*/
1.2.9 What are assessor properties
- Sometimes properties values are not needed or get changed or computed whatever the case, setter provides the way to assign values to properties. You can set the value to the property or provide the setter method to do it, both can not be done at the same time. If setter or getter is used property may be called as
assessor propertiesto differentiate from Data properties.
If a property has both getter and setter method it is called read and write property. To make the property readable only, one can only provide getter method. Similarly if it has only setter it acts as a write only property which makes it unique in a way that Data properties can not be made write only unless ECMAScript-5 attribute write is set to false.
In the example below one Data property start is set to an object as well as Assessor property ( by using the key word get). The name of this property is startPlusPlus, since only getter is used it is only readable. Note the clever technique used here , it is the getter which computes the value of assessor property using given expression. It should be noted that a new property does not exist until it is accessed but its initial value is based on Data property.
1.2.10 Read only assessor property
1'use strict'
2var obj = {
3 start: 0, // Data property
4 get startPlusPlus() {
5 return ++this.start
6 } // Assessor property
7}
8obj.startPlusPlus = 10 // in non strict mode ignored silently
9/*TypeError: Cannot set property startPlusPlus of #<Object> which has only a getter*/
10
11console.log(obj.start) //0
12console.log(obj.startPlusPlus) // 1
13console.log(obj.startPlusPlus) // 2
1.2.11 Read and Write assessor property
1var obj = {
2 seed: 0,
3 get randomNumber() {
4 return Math.floor(Math.random() * this.seed)
5 },
6 set setSeed(num) {
7 this.seed = num
8 }
9}
10obj.setSeed = 256 // This will yield a number between 0 and 255
11console.log(obj.seed) // 256
12console.log(obj.randomNumber) //249
- It should be noted that get and set may look like functions but they are not. This getter and setter method was provided in ECMAScript-3 API. Now ECMAScript-5 has define property method which is more elegant and provide options which were not possible earlier. For example prior to ECMAScript-5, properties were writable, enumerable and configurable (set to true by default) and there was no way to change this behaviour. Therefore it is better to avoid set/get API of ECMAScrit-3 and use ECMAScript-5 instead.
1.2.12 Like other variables object’s properties have some attributes
When any property is added to JavaScript object it automatically gets some attributes associated with it. Thus property does not have only values but also other attributes namely writeable enumerable, and configurable. These attributes tells if the property can be enumerated ( if enumerable), can be changed ( if writeable ) and these writable and enumerable can be reset ( configurable) that is the status can neither be changed nor the property can be redefine. Thus the default behaviour is shown below
1// This is the behaviour of Repell shell
2var x = 10
3console.log(Object.getOwnPropertyDeiscriptor(global, 'x'))
4/*{ value: 10,
5 writable: true, // can be updated
6 enumerable: true, // can be enumerated when needed
7 configurable: false // the above behaviour can not be changed
8 }*/
9// This is the behaviour of file.js where global is not a host variable,
10x = 10
11console.log(Object.getOwnPropertyDescriptor(global, 'x'))
12//{ value: 10,writable: true,enumerable: true,configurable: true }
13// This the behaviour when an object is defined whether in file.js or in REPELL
14var o = { y: 23 }
15console.log(Object.getOwnPropertyDescriptor(o, 'y'))
16//{ value: 23,writable: true,enumerable: true, configurable: true }
By default if these attributes are not set, then property can be changed and enumerated and this behaviour can not be changed.To have control over this behaviour, ECMASCript-5 provides a method which can be used to define a property with greater control. Once this function is used to set the value of a property and if others are not set. Then by default they are set to false thus this property can not changed and this behaviour can not altered. Thus you need to pay attention when using this method.
As it is shown above when working within nodeJS environment, a variable defined in an object can be redefine with Object.defineProperty() method which allows its attributes to be changed as discussed in section below.
1var o = { y: 23 } // by default attribute writeable is true
2o.y = 100 // value is updated
3console.log(o.y) // 100
4Object.defineProperty(o, 'y', { writable: false })
5o.y = 200 // fails silently
6console.log(o.y)
1.2.13 Adding properties with ECMAScript-5 approach
- ECMAScript-5 provides a built in function to set the attributes of the property of the object. There are two functions to define the property one is to use when defining only one property and the other one is when defining more than one.
1var obj = {}
2Object.defineProperty(obj, 'x', { value: 200 })
3console.log(obj.x) //200
4console.log(Object.keys(obj)) // if not define enumerable is false
5obj.x = 300 // can not be done as if not define, writeable is false.
6console.log(obj.x) // 200 remains same
7// it can not be redefined as well
Let’s define all the attributes as shown below.
1var o = {}
2Object.defineProperty(o, 'x', {
3 value: 100,
4 writable: false,
5 enumerable: true,
6 configurable: false
7})
8console.log(o.x) // 100.
9// Since writable is set to false it can not be re assigned any value.
10o.x = 20 // silent failure
11// In strict mode it is flagged as a TypeError: Cannot assign to read only property 'x' of object
12console.log(o.x) // 100
13console.log(Object.keys(o)) // [x] . Since enumerable is true
14// Try to reassign x
15Object.defineProperty(o, 'x', { value: 200, writable: true })
16//TypeError: Cannot redefine property: x
- The above shows that if a property is defined with
configurable : falsethe same property can not be redefined at all unless when it was being defined, was set to true. It should be noted that, these attributes are set to individual properties and not to the object. Thus other properties can be added and configured.
1var o = {}
2Object.defineProperty(o, 'y', {
3 value: 100,
4 writable: false,
5 configurable: true
6})
7console.log(Object.keys(o)) // []
8Object.defineProperty(o, 'y', { enumerable: true })
9console.log(Object.keys(o)) // [y]
1.2.14 Setting more than one property Object.defineProperties()
1var obj = {}
2console.log(obj)
3Object.defineProperties(obj, {
4 x: { value: 2, writable: true, configurable: true },
5 y: { value: 3, writable: true, configurable: true },
6 r: { value: 10, writable: false, configurable: false }
7})
8console.log(Object.keys(obj)) // []. empty
9console.log(obj.propertyIsEnumerable('x')) // false
10// Following loop will not run because condition is not true.
11for (var prop in obj) {
12 console.log('properties are ' + prop)
13}
14// Either change the attribute individually
15Object.defineProperty(obj, 'x', { value: 20, enumerable: true })
16// Or use the following to see the property only
17console.log(Object.getOwnPropertyNames(obj)) //[ 'x', 'y', 'r' ]
18console.log(Object.getOwnPropertyNames(obj).sort()) //[ 'r', 'x', 'y' ]
1.3 Object Attributes
- Not only object’s properties have attribute but object itself has attributes which defines its behaviour. These attributes are
prototype,class and extensible.
1.3.1 Prototype Attribute of an Object
- ECMAScript-5 provides a way to get object’s prototype by using
Object.getPrototypeOf(target)method. Before ECMAScript-5 it was made possible by using the object inherited property__proto__or usingo.constructor.prototypefor the object created by a given prototypeObject.create(fromP)method. To find out if one object is prototype of the other or is part of the prototype chaina.isPrototypeOf(b)( to find out if “a” is prototype of “b”) is used.
1function fn() {
2 var age = 10
3}
4var a = { size: 10 } // a gets default prototype
5var b = Object.create(a) // b is created from prototype a
6var c = Object.create(fn) // c is created from prototype fn
7console.log(Object.getPrototypeOf(a)) // {}
8console.log(Object.getPrototypeOf(b)) // {size:10}
9console.log(Object.getPrototypeOf(c)) // [Function fn]
10
11console.log(Object.getPrototypeOf(a) === Object.getPrototypeOf(b)) // false
12console.log(Object.getPrototypeOf(b) === Object.getPrototypeOf(c)) // false
13console.log(Object.getPrototypeOf(c) === Object.getPrototypeOf(a)) // false
14
15//Constructor Prototype
1.3.2 Class Attribute
- Since JS never had any classes or class syntax before ECMAScript-5. Thus more attention to be paid here. In JS the user type is created from the
constructor functionand this is the function which acts as class of its type.
1function Animal() {
2 var breath = true
3}
4var rabbit = new Animal()
5console.log(rabbit)
1.3.3 Extensible Attribute
If the properties of the object can be added to the object after its creation the object is said to be extensible. All built in and user defined objects are implicitly extensible unless they are explicitly made non extensible. To make it non extensible, it can be passed to Object.preventExtensions() once is it non extensible it locks down the object into a locked state and prevent it from the outside tampering.
1var o = {} // By default it is extensible
2o.x = 10
3console.log(o) // { x: 10}
4Object.preventExtensions(o) //can not be extended
5o.y = 10 // fails silently , y is not added
6console.log(o) // Still { x: 10}
7// property is still configurable and can be changed and deleted
8o.x = 100
9console.log(o) // { x: 100}
10delete o.x // it can still be deleted
11console.log(o)
12o.x = 20 // fails silently because it can not be extended.
13console.log(o)
Though the above code prevent the object to be extended but already existing properties can still be set and deleted. To make an object non extensible and as well as make its properties non configurable another method Object.seal() can be used instead of the above as shown below. Making object properties non configurable means that whatever attributes the properties are set with can not be reset. If a property is set with writable true, it can cont be made false because it can not be re configured.
1var o = { x: 10, y: 20 }
2Object.seal(o) // Making it sealed
3o.z = 100 // fails silently
4delete o.x // fails silently
5console.log(o)
6// changing the value of properties
7o.x = 1000
8o.y = 898 //if it was allowed before,will still be allowed
9console.log(o) // { x: 1000, y:898}
10// Properties can also be reset because before sealing the object
11// their writable state was set to true
12console.log(Object.isExtensible(o)) // false
13console.log(Object.isSealed(o)) // true
14console.log(Object.isFrozen(o)) // false
Object which needs to be provided high level protection can be frozen by using Object.freeze(o). If an object is made frozen, it automatically prevents its extension and makes it non configurable but at the same time it also makes its properties read only. To see if the object is frozen one can use Object.isFrozen() just like other method used to see if the object is sealed Object.isSealed(o) or extensible. Object.isExtensible(o)
1var o = { x: 20, y: 30 }
2Object.freeze(o)
3console.log(Object.isFrozen(o)) //true
4// All below commands fails silently
5o.x = 100 // can not be reset
6delete o.y // can not be deleted
7o.z = 200 // new properties can not be added
8console.log(o) // {x:20, y:30}
Object main services and static methods
All JS objects by default share services from their corresponding prototype. These services are mainly methods which are used by newly created instance. An instance of Array class gets to share everything from the Array.prototype and being an object it also get to share from Object.prototype and so on until the prototype inheritance reaches the point where the prototype becomes the null. Apart from these shared methods, a programmer often use static method define on Object constructor which are given below.
1var arrayProp = Object.getOwnPropertyNames(Object)
2var fun = arrayProp.filter(function (element) {
3 return typeof Object[element] === 'function'
4})
5console.log(JSON.stringify(fun))
6/* ["assign","create","freeze","getOwnPropertyDescriptor","getOwnPropertyNames","getOwnPropertySymbols","is","isExtensible","isFrozen","isSealed","keys","preventExtensions","seal","defineProperty","defineProperties","getPrototypeOf","setPrototypeOf"]
7 */
When discussing about shared services from the prototype object, there are some methods which can be over ridden to provide object specific details. For example toString() method which gets shared from Object.prototype when applied to any object does not show much. Note whenever you apply concatenating operator + to something which is not an string JS automatically apply toString() function to convert it string.
1var o = { x: 1, y: 2 }
2console.log(o.toString()) // [object Object]
3console.log(o) //{x: 1, y: 2}
4console.log(o + '') // [object Object]
5console.log(JSON.stringify(o)) //{"x":1,"y":2}
Because there is no useful information provided by the toString() method, the other classes defines their own behaviour of toString() method. For example the Array , Date and Function classes over rides this function to provide useful information as shown below.
1var y = [123, 4567] // An array object
2console.log(y) // [123,4567]
3console.log(y.toString()) // 123,4567
4var fn = function () {
5 console.log('I am a function')
6}
7console.log(fn) // [Function: fn]
8console.log(fn + '') // function(){.....}
Creating objects with Object constructor i.e., using new operator
Programmers who come from class based object oriented background often get puzzled with the way JavaScript works. For example it is the very basis of Object oriented programming to instantiate the object in order to create it from its class. And to do so they are programmed to use class constructor with the help of new operator. In JavaScript the following method is used to create either user defined or pre defined objects with new operator. They are known as built in constructor.
1// User defined object
2var point = new Object() //same as {}
3point.x = 10
4point[y] = 20
5console.log(point)
6// Predefined object
7var myObject = new Object() // same as creating from literals {}
8var grid = new Array() //same as creating from square brackets []
9var today = new Date() //No short cut present
10var word = new RegExp('JavaScript') //No short cut
No matter which book or article you read, there will be an advice “Don’t use
new” to create an object, use object literal{}instead.
Both methods do the same job as long as you are not doing any special computation which requires memory optimization. Keep in mind with object literal no instantiation is required and your code is optimized as far as less typing is concerned, on the contrary with new more typing is involved and object instantiation is performed.
Objects have behaviour
Objects not only have some properties ( object’s attributes) attached to them but they contain methods. Functions in JS, when defined in object are called methods ( and in all other languages too). A function’s typical job is to do something (compute some values) and return the result. This can be understood as objects’ behaviour. In JavaScript object’s properties are assigned to functions to exhibit the behaviour of an object and known as methods.
1var point = {
2 x: 10,
3 y: 20,
4 move: function () {
5 console.log('point has moved')
6 }
7}
8// invoking a function
9point.move()
10//or
11point['move']()
Calling or Invoking objects’ methods
In above code apart from x and y the word move is also a property of the object but since move property is assigned an anonymous function. It behaves like function identifier and regarded as object’s method. As we have learned before to execute this method we will have to use trailing brackets when invoking a function. Thus point.move() will invoke this function. It will be interesting to note that just like the other way of accessing the property i.e., using square brackets notion, you can also use square bracket notation to invoke the method. After all it is a legal property of this object. To do so, point['move']() will be used. But it is not the accepted practise among programmers. Hence be aware of what can be done and what is accepted as a good practice.
Note: When a method is invoked upon on any object. A key word
thisis set/given to that method by providing it a way to access objects’ variables/properties.
Accessing object’s properties from within its own method
When a function is defined in an object it can only be invoked through that object. Therefore inside the definition of the function referring to the same object needs to be done explicitly by using the object name or with the keyword this which is given to function when it is invoked with respect to its execution context.
1var point = {
2 x: 10,
3 y: 20,
4 move: function () {
5 //console.log(x,y) // error x and y are not accessible here
6 console.log('x is ' + point.x + ' while y is ' + point.y)
7 console.log('x is ' + this.x + ' while y is ' + this.y)
8 }
9}
10point.move()
11console.log(point.x) // both x and y are public members
12console.log(point.y)
Object’s properties are mutable
In the above code the values of x and y are accessible to everybody (public ), what it means that a user can access the values using the object without having to worry about anything. Not only the values can be accessed but changed easily as done here. In fact, the mutability of any object's properties reflects the objects’ change in state.
1var point = {
2 x: 10,
3 y: 20,
4 move: function (dx, dy) {
5 this.x = this.x + dx
6 this.y = this.y + dy
7 console.log('new x is ' + this.x + ' while new y is ' + this.y)
8 },
9 deleteThem: function () {
10 delete this.x
11 delete this.y
12 console.log('new x is ' + this.x + ' while new y is ' + this.y)
13 }
14}
15point.move(100, 10) // object state is changed
16point.deleteThem() // object state is changed
Object can contain other objects as its properties
It is very common in JavaScript code to see an object containing another object for one or the other reasons. It may be that they have containing relationship or the programmer has chosen this design. Let say I have a car that has an alarm. I decide to have an alarm property of the car as an object.
1var car = {
2 make: 'Toyota',
3 model: 'Prius',
4 // alarm is a property of a car which itself is an object
5 alarm: { type: 'standard', isModified: false, isOn: true },
6 starts: function () {
7 if (this.alarm.isOn) {
8 console.log('starting')
9 } else {
10 console.log('can not start')
11 }
12 }
13}
14car.starts() //starting
15car.alarm.isOn = false // car state is changed
16car.starts() // can not start
Enumerating object’s properties
Often you need to see what is present in concerned objects. JavaScript provides a built in function known as for...in loop . It loops through the given object and its prototype chain and returns properties names along with their values in a string format. A very handy function to see what is present in your object. There are some other functions which we will discuss later on.
1var courseNames = { x: 1, y: 2, z: 11 }
2for (var prop in courseNames) {
3 console.log('courseNames.' + prop + ' =' + courseNames[prop])
4}
Since there was no prototype chain the function returns not only the property names but associated values of the target object only. When retrieving with for...inloop it also retrieves methods and the other objects from the target object therefore you need to write code to filter them out as done following.
1var courseNames = {
2 x: 1,
3 y: 2,
4 z: 11,
5 anyFunction: function () {},
6 emptyObject: {}
7}
8var propName // you can add code to filter objects as well if you need
9for (propName in courseNames) {
10 if (typeof courseNames[propName] !== 'function') {
11 console.log(courseNames[propName])
12 }
13}
In order to filter any prototype values use hasOwnPropertyNames() in your logic
When enumerating which function to use
If the object’s property enumerable attribute is set to true ( thus enumerable) it can be enumerated using either for...inloop or Object.key(obj) method. The difference between them is that for...in loop enumerates properties in the prototype chains as well ( if there is any ) while Object.keys() method only returns the properties of object’s own enumerable properties( only enumerable ).
1var courseNames = {
2 x: 1,
3 y: 2,
4 z: 11,
5 anyFunction: function () {},
6 emptyObject: {}
7}
8// Use of Object.keys(obj) function
9console.log(Object.keys(courseNames))
10// will return [ 'x', 'y', 'z', 'anyFunction', 'emptyObject' ]
To see if the property is enumerable or not use propertyIsEnumerable(prop) function on the object whose property attribute is to be checked.
1var courseNames = {
2 x: 1,
3 y: 2,
4 z: 11,
5 anyFunction: function () {},
6 emptyObject: {}
7}
8console.log(courseNames.propertyIsEnumerable('x')) // true
9console.log(courseNames.propertyIsEnumerable('abc')) // false
10// Note the use of quotation marks, the property name must be quoted
There are other functions which can provide help about properties and their associated attributes provided by EcamaScript-6 which we will be using later on like getOwnPropertyDiscriptro() function and getOwnPropertyNames(obj)
Looking for a particular property
Often there is a case when you only want to look for a unique property to make sure whether it is present or not in your object. There are different approaches present some are discussed below. The conventional method would be to write a loop and go through each and every property and comparing the one you want.
Be clear what exactly you are comparing is it a property key or its value.
1var courseNames = { Ms012: 'Cognitive Science', Bs310: 'Physics' }
2//checking through property's value
3for (var prop in courseNames) {
4 if (courseNames[prop] === 'Cognitive Science') {
5 console.log('Yes ' + courseNames[prop] + ' is present')
6 }
7}
8//checking through property's key
9for (var prop in courseNames) {
10 if (prop === 'Bs310') {
11 console.log('Yes ' + prop + ' is present')
12 }
13}
The above does the job but as we said earlier there are other more elegant approaches present. Though there are subtle differences but both does the same job.
1var courseNames = { Ms012: 'Cognitive Science', Bs310: 'Physics' }
2if ('Ms012' in courseNames) {
3 console.log('Yes it is present')
4}
5//or
6if (courseNames.hasOwnProperty('Bs310')) {
7 console.log('Yes it is also present')
8}
What goes behind Object creation
When an object is created with its literal {} notation or using new Object() constructor, only and only one instance of a specific type is created. And there is no other object like it. Thus var o1 = {x:1}; and var o2 = {x:1}; are not same at all. They are only equal to themselves.
1var o1 = { x: 1 }
2var o2 = { x: 1 }
3console.log(01 == 02) //false
4console.log(01 === 02) //false
5console.log(01 == 01) //true
6console.log(02 === 02) //true
In memory they are two separate objects holding different spaces. The object identifier
o1ando2both are basically the pointers to their respective objects.
1
2 {x:1} {x:1}
3 ++++++++++ ++++++++++
4 | | | |
5 | | | |
6 ++++++++++ ++++++++++
7 AFE12B FEBC41
8 ^ ^
9 | |
10 | |
11 o1 o2
- Since when object is created, the question comes in mind how to delete them. JavaScript is a dynamic language and takes this responsibility itself. It is the job of the garbage collector to delete any dangling object which has no reference to it. But if you want to release memory you may assign it to a
nullvalue but it does not guarantee an immediate release of memory. There are some other techniques used to delete the memory.
Note: You can not delete object using delete operator as you would delete any variable or any object’s property if it is deletable.
1delete o1 // not allowed and not possible
2delete o1.x // allowed and possible
Object testifies itself
When an object is created, it also get another object created by the system that works as a prototype of newly created object. The newly created object not only has access to its own properties but also the properties of its prototype. If a newly created object is searched for a property that it can not find, its prototype is searched and the search goes on until the top of chain is reached. This secrete internal link of invisible objects is known as prototype chain.
For example, in above case when o1 is created with one property but it automatically inherits ( gets available ) some properties and methods from a special object named prototype which is defined in Object as its one of the properties thus can be accessed as Object.prototype.
To get more detail about this special object which a newly created object receive you may take the help of of its own provided methods, such as toSring , to String() , getPrototypeOf() and so on. These available methods ( or some may call it services) and others are always available to the object you create to ease your work as shown below
1var stomach = {}
2var apple = { juicy: true }
3var banana = new Object({ juicy: false })
4var pear = Object() // forget to write new
5console.log(Object.getPrototypeOf(stomach)) // {}
6console.log(Object.getPrototypeOf(apple)) // {}
7console.log(Object.getPrototypeOf(banana)) // {}
8console.log(Object.getPrototypeOf(pear)) // {}
9console.log(apple.constructor) //Object
10console.log(banana.constructor) //Object
11console.log(stomach.constructor) //Object
12console.log(pear.constructor) //Object
13//you may use typeof operator as well
14console.log(typeof stomach) // object
15console.log(typeof stomach.prototype) //
The code above testifies few things:
- Objects created with a literal
{}or with a constructornew Object()also get a prototype object{}to share its behaviour. - They all are created from the same constructor.
- If you forget to write
newbefore built-in constructor it is taken care of. - Objects created by user get number of services available to it automatically by design. These services are exposed by the
Object.prototypeobject{ }. - Two internal links are established among user defined object and the object that provides services and the object that creates it.
It is important to understand that if this internal link is lost your program may not behave the way it is expected. The constructor property points to the constructor that creates it. If you write your own constructor function then this property will point to the user defined constructor. Let see this whole in figure given below
1 var anObject = {}; or var anObject = new Object()
2
3 prototype property of Object
4 | |
5 Object() | V
6 ============= v ==========
7 |constructor | Object.prototype--->|prototype |- constructor:
8 | object | | object |- __proto__:
9 ============= ========== - |
10 ^ ^ -hasOwnProperty()
11 | | -isPrototypeOf()
12 | | -..... |
13 | | -..... |
14 | | |
15 | | services shared
16 anObject.constructor anObject._proto_
17 ==========
18 |anObject |
19 ==========
Assigning objects to other variables
Once an object is created it can be assigned to any other variable. In JavaScript this assignment is known as shallow copying in object oriented programming. Thus following code does not create a new object but another pointer to the same object already present in the memory.
1 var o3 = o1;
2 console.log("Are they equal " + ( o3 === o1));
3 o2 = null; //o2 no longer points out to previous space in memory
4 // it has been de referenced
5
6 {x:1}
7 ++++++++++
8 o1 -----> | | o2 ---> null
9 o3 -----> | |
10 ++++++++++
11 AFE12B
JavaScript Objects are mutable and manipulated by reference
It is clear from the above example that the objects are passed by reference when they are assigned to new variables or passed to any function. Passing by reference put more responsibility upon the user. If an object gets changed by one reference the change is shown by others immediately.
1var o1 = { x: 1 },
2 o2 = { x: 1 },
3 o3 = { x: 1 } // They are all different objects
4// but now they are going to refer same object
5var o1 = (o2 = o3 = { x: 1 }) // All referring to same object
6// the original objects memory taken by o2 and o3 are deleted automatically ( ??)
Object.prototype and Prototype object are different things
For new comers the term prototype becomes confusing. In classed based Object Oriented languages, class provides the blue print or die for objects of same type to be created. These objects are known as instances of a class and they share the services provided by the class. In JavaScript since there has been no concept of classes until recently when ES6 has come out in the market.
When programmer started using c and other contemporary languages twenty years ago they did not have thousand lines of code already written and ready to be used available for their programme. They had to write everything from scratch. But then came along Class based Object Oriented programming providing libraries and other facilities to be used without re inventing the wheel. Most of the time the code reuse was achieved by having the top level Object already written for the user which would expose commonly used services for the user defined newly objects. And this technique was known as inheritance which involved the concept of classing and sub classing by way of inheriting properties from their super class based on the notion of having a relation known as is-a or a kind of. For example, rabbit is an animal so is a frog and others. They may have same attributes and some would differ and so on. Hence the idea was to keep the top class more generic and subclasses specific.
Since JavaScript was not at all an Object Oriented language, this is-a relation was achieved using techniques called composition and containment as opposed to inheritance. Therefore the term prototype was used to indicate the top most class which types of object were needed. In JavaScirpt When you create any object, the language provides a prototype object to the new object to share the services from. This is a default behaviour of the JS. To manipulate the new object JS allows you to use a global object called Object, it should be interested to know that the prototype object which were given to you to use the services is also defined as property of this Object thus written like Object.prototype. Having explained this, it is important to understand that when a user wants to create a class ( since JavaScript never provide the facility to write classes), it was left to define their own constructor function which acted like super class and came to be known as the Prototype for creating the same type of objects.
Object.prototype means that the Object has a property named prototype which itself is an object. And its properties gets inherited automatically by any object created by either object literal or Object constructor. { we will discuss this automatic inheritance later on }
A rough shape of Object
1 Object = {
2 .....//other properties
3 .....
4 prototype: {
5 constructor:....
6 _proto_:.....
7 .....
8 }
9 ....//other methods
10 hasOwnProperty: function(property){.....}
11 isPrototypeOf: function() {......}
12 propertyIsEnumerable: function(){......}
13 toString: function() {.....}
14 ......
15 }
Object.prototype itself, does not inherit any property from any object. To see if it is true or not simply type console.log(Object.getPrototypeOf(Object.prototype)); and you will get the null answer.
All built in constructors first inherit properties from their corresponding built in constructor and then from Object.prototype as well. This inheritance is known as prototype chain.
All built in objects like Array , Date , RegExp etc are also type of Objectthat is they descend from top most object. Similarly they all get to share code from their corresponding prototype which in turns also inherit code from object prototype. For example new Date() and new Array() first inherit properties from Date.prototype and from Array.prototype respectively but also inherit properties from Object.prototype too.
To find out the exact constructor of a newly created object we can use constructor as inherited property, Object.prototype.constructor which returns the function constructor that creates given object’s prototype. In other words when a new object is created it inherits this property which points to the constructor which created the new object.
1var o1 = {},
2 today = new Date(),
3 grid = new Array()
4var n = new Object(1)
5
6console.log('o1 is created by ' + o1.constructor) // function Object()
7console.log('today is created by ' + today.constructor) //function Date()
8console.log('grid is created by ' + grid.constructor) //function Array()
9
10// Another way of testing would be
11if (n.constructor === Number) {
12 console.log('n is created by ' + n.constructor) //function Number()
13}
14// Even a function in JavaScript is created using Function() constructor
15var f = function () {}
16if (f.constructor === Function) console.log('f is created by ' + f.constructor)
Creating Object with Constructor function
Creating objects with object literal or Object constructor both provides a way to create a single object pattern. What it means that you are only able to create only one object of a particular type. To create multiple objects of a same type you need to use
Constructor function. That is to create as many instances as you want from a blue print.
In OOP you can write a class and create many instances from that blue print. In JavaScript making different instances from its prototype is achieved using a technique called creating objects with Constructor Function. The following code writes a Constructor function so that multiple instances of this function can be created. This is an interface like a class providing a constructor pattern to create same type of objects.
1// Constructor function,a prototype for other objects, it acts like a class
2function Animal(itsName) {
3 //note Animal with Capital A to identify as a CTOR
4 this.name = itsName
5}
6//Create different instances of Animal using new operator from its prototype
7var rabbit = new Animal('Bunny')
8var cat = new Animal('Nimy')
The code var rabbit = new Animal("Bunny") is just like creating an instance from its class in class based Object Oriented Languages. But here we know that Animal is not a class but a mere function declaration. In JavaScript it is one of the ways to create multiple instances of a same object.
It is either rabbit or cat both have their own data and do not share their state from each other. Thus the code console.log(rabbit.name); will yield to “Bunny” while the code console.log(cat.name); will yield to “Nimy”. If you like to add a variable which gets available to all instances of the class then you have to make it a class variable not the instance variable or what is known as static variable. A static variable is shared among all instances of a same class and can only be invoked by the class name itself. It can not be invoked by the instance of that class. A class can not only have static properties but can also have static methods which can only be invoked by the class itself. The example of static methods are Object class methods most of them are only static and can only be used by the Object itself and not by the instances of the Object class. Object.create(),Object.getPrototypeOf() are just two examples of static object defined on Object.
1function Animal(itsName) {
2 Animal.counter = (Animal.counter || 0) + 1
3 this.name = itsName
4}
5console.log(Animal.counter) // undefined
6var rabbit = new Animal('Bunny')
7console.log(Animal.counter) // 1
8var cat = new Animal('Nimmy')
9console.log(Animal.counter) //2
10condole.log(rabbit.counter) // undefined
Though the above is a very simple example yet explains the point. You can also add functions to the constructor function.
Adding properties
It is important to note that member variables of an object known as properties ( can either be a simple property or a method) can be added to an individual object or to objects’ prototype.
Adding properties and methods to individual objects
1function Animal(itsName) {
2 this.name = itsName
3}
4var rabbit = new Animal('Bunny')
5rabbit.maxAge = 18
6
7var dog = new Animal('Wosh')
8dog.maxAge = 16
9dog.barks = function () {
10 return this.name + ' says Hello'
11}
12
13var cow = new Animal('mo')
14cow.maxAge = 20
15cow.milks = function () {
16 return 'Hi, it is delicious'
17}
18
19console.log(rabbit) //{ name: 'Bunny', maxAge: 18 }
20console.log(dog) //{ name: 'Wosh', maxAge: 16, barks: [Function] }
21console.log(cow) //{ name: 'mo', maxAge: 20, milks: [Function] }
22console.log(cow.milks()) //Hi, it is delicious
23console.log(dog.barks()) //Wosh says Hello
In above code the property maxAge which is shared by all instances should be added directly to the constructor function. So it is shared among all instances. However there are some situations where a new property is needed to be added dynamically in that case it is added to prototype object instead of adding separately to each object.
Adding properties to prototype object
In order to add a property or a method to the function object, JavaScript allows a built-in property to be used to achieve this task. This property is called prototype and is only available to the function object and not to the object. Thus the code Animal.prototype.maxAge will add property maxAge to the prototype object. And in this case the prototype object is the default prototype object Object.prototype.
1function Animal(itsName) {
2 this.name = itsName
3}
4Animal.prototype.maxAge
5var rabbit = new Animal('Bunny')
6rabbit.maxAge = 18
7
8var dog = new Animal('Wosh')
9dog.maxAge = 16
10
11var cow = new Animal('Mo')
12
13console.log(rabbit)
14console.log(dog)
15console.log(cow)
Note: Adding property to a prototype object gets available to be used by all instances of Constructor function but it does not become the member of a constructor function. To add a new member to constructor function it has to be added manually. You can not add a new property to a constructor function by
Animal.newproperty. AsAnimalis not an object.
How CTOR function( the prototype ) initialized
- The code
var cat = new Animal("Nimy")when executed does the following things.
- It creates an empty object and keep a reference on it by using a reserved word
this. - An internal link is established between this newly created object and
Object.prototypeso that it inherits properties fromObject.prototypemaking all properties and methods available to the newly created object. - It also sets the constructor property of the
Object.prototypetoAnimal - This object is returned implicitly if no other object is returned explicitly from this constructor.
This newly created object now becomes an instance of an Animal which you have defined.
Public and Private members & use of this in Constructor function
Members variables which can be accessed directly by the instance of the class after they have been instantiated are regarded as public members. By design objects have to provide public methods which can be invoked upon the object and inside the implementation of the object member variables are accessed keeping them private. In Js when creating an object with constructor function, private variable are written using var keyword which provides them function scope making them impossible to access from the instance variable outside the constructor function.
1//file-name:13.js
2function Animal(itsName) {
3 this.name = itsName //public member
4 var breathes = true //private member
5 var age = 1
6 this.isAlive = function () {
7 //public member
8 return breathes === true ? 'yes' : 'no'
9 }
10 var changeAge = function (x) {
11 //private member
12 age = +x
13 }
14}
15var rabbit = new Animal('Bunny') // A new object is created and returned
16console.log(rabbit.name) // allowed , public members
17console.log(rabbit.breathes) //undefined, private members
18console.log(rabbit.isAlive()) //allowed
19rabbit.changeAge(1) //error ;not allowed, it is not visible here
From the above it should be clear that all local variables or functions defined using var key words make them private members. While those defined by this keyword become public members.
Can the new instance testifies itself
The instance of Animal which is just created and now referenced by rabbit should be able to give some detail about itself if it is an instance of Animal. To get those details we take the help from functions that it inherits implicitly as well as with the available operators.
1//using inherited methods, a robust way of checking
2console.log(rabbit.constructor) // [Function:Animal]
3console.log(Object.getPrototypeOf(rabbit)) //Animal {}
4//using operators , can be deceptive in some situations
5console.log(typeof rabbit) //object
6console.log(rabbit instanceof Animal) //true
The above code testifies that the object created and returned is the right one you intended.
Forget to use new! face the music
Imagine you create an instance of Animal and forget to use the new operator var cat = Animal("Nimmy") . There will be no error nor any warning but your programme will not behave the way you would want. Therefore it is best practice to use code pattern . A code pattern is just a unique way of writing some code which makes/forces code do what it is supposed to do despite lacking of strongly typed language. Now what happens if the new is not typed.
1var cat = Animal('Nimmy')
2console.log(cat.constructor) // error: cat is not an object
3console.log(Object.getPrototypeOf(cat)) //error
4console.log(typeof cat) //undefined
5console.log(cat instanceof Animal) //error
Without the use of new operator before the constructor function no object gets created thus the use of inherited properties results in error. The members of Animal constructor function does not get bind to this and become the property of the global object. It is just like variables declared inside the function without the keyword var are regarded as implied global. Thus can be accessed using global.name , window.name or anything else depending upon the host environment. To see what exactly this refers to you can add this code in your programme console.log(this).
Why not flag it as an error
Forgetting to write new, raises issues which were not anticipated and tackled when constructor function was written. In an ideal situation an error should have been raised warning the mistake but it does not happen. To tackle this problem there has been many ways and one of them is to use code pattern while the other is to raise the error using JavaScript provided throw. Using code pattern or any other approach is a way to tackle the problem but the language itself provide the safe mechanism and urges programmer to use it which is known as use strict. We will talk about it coming topic
Tackling issue with Code Pattern
To make sure that in case of forgetting to write new your code behaves correctly. You need to change the code of constructor function by explicitly returning an object as done below.
1 //file-name:13-1.js
2 function Animal(itsName) {
3 var temp = {}
4 temp.name = itsName;
5 return temp
6 }
7 var dog = new Animal("wof");
8
9 console.log(dog.constructor); //[Function:Object]
10 console.log(Object.getPrototypeOf(dog));// {}
11 console.log(typeof dog); //object
12 console.log(dog instance of Animal); // false
The above make sure that an object is always created and returned. It may be interesting to note that the convention of writing this pattern uses a that identifier instead of temp, but you may use whatever you like. It is also not necessary to return a named object you may return an object using its literal as shown below.
1 function Animal(itsName){
2 return {
3 name: itsName;
4 }
5 }
Problem with the code pattern approach
Though code pattern seem to solve the issue encountered by forgetting to write new but raises others concern. The whole chemistry of our idea to be able to create multiple instances from a prototype is changed for the following reasons;
- First of all the object returned is not an instance of an
Animalbut a generic object. - Its prototype is not
Animalbut an empty object{} - Its constructor is
ObjectnotAnimalany more.
In short it all happens because the code pattern did not do the job fully. it did create an object took care of problem arising from the issue of forgetting to write new but failed to provide the prototype link b/w newly created object and the object that it inherits from.
How to fix the prototype link in constructor function
To fix this issue in constructor function, a logic is added to check if an executing context is an instance or not, if not we call it with a new operator that is a self execution . Thus new constructor function would look like as shown below.
1function Animal(itsName) {
2 if (!(this instanceof Animal)) return new Animal(itsName) // execute itself
3 this.name = itsName
4}
The above approach seems to work fine even if we forget to write new operator with constructor function. This technique is known as scope-safe and adopted internally by most built in constructor to first see if the user has called the constructor using new operator or not, otherwise it executes itself. The above code can also use the arguments.callee but it is not preferred and may be remove from new versions.
Tackle this issue by raising as an error
Another way to tackle this problem of forgetting to write new operator is to nip the evil in the bud, approach. A logic is provided in your constructor to see if it is invoked with new or not if not raise an error as done below.
1function Animal(itsName) {
2 if (!(this instanceof Animal)) throw new Error('call with new keyword')
3
4 this.name = itsName
5}
A Real World example of a constructor function
MetalSmith is a static web site generator which exposes a function as a module named metalsmith. The declaration of this function is shown below.
1module.exports = Metalsmith
2
3/**
4 * Initialize a new `Metalsmith` builder with a working `directory`.
5 *
6 * @param {String} directory
7 */
8
9function Metalsmith(directory) {
10 if (!(this instanceof Metalsmith)) return new Metalsmith(directory)
11 assert(directory, 'You must pass a working directory path.')
12 this.plugins = []
13 this.ignores = []
14 this.directory(directory)
15 this.metadata({})
16 this.source('src')
17 this.destination('build')
18 this.concurrency(Infinity)
19 this.clean(true)
20 this.frontmatter(true)
21}
22
23// only plugins and ignores are properties which are assigned an empty array the rest are functions. These functions are declared somewhere in the programme
Adding methods to constructor function
Once you overcome the problem of creating the constructor function, you are through to creating different instances from this prototype. Every instance you create from this blue print gets its own copy of members variable. Say if you create ten instances of from Animal constructor. Each instance gets its own copy of members ( variables and functions ).
There is nothing wrong with this in fact this is exactly what we wanted to achieve . To be able to create multiple instances of a same type. However we have to reconsider the issue of dealing with members which are not ordinary variables but functions added as are part of the constructor function. The reason being that ordinary variables and functions differ in many ways . Every time a function is created there are more overheads to be considered as compared to ordinary variables and this can lead to memory optimization issues.
Using prototype property to add functionality / Augmenting Built-in Objects through prototype
First of all be clear that JavaScript provides you many built in constructor of different type to start creating your objects without writing your own from the scratch. These built in objects behave like a die ( a moulding die ) or commonly knowns as blue print or prototype. In addition to creating the object from this constructor, JavaScirpt also allows you to add different services which may not be provided by built in constructor. When you add extra functionality into built in object’s prototype, the object is said to be augmented.
1var pen = {}
2pen.writes() //error write is neither a member of pen nor its prototype
3
4// get the prototype of pen object and add this function to it.
5Object.getPrototypeOf(pen).writes = function () {
6 console.log('It works')
7}
8//call this function on pen
9pen.writes() // It works
10// create a new object with the same prototype {} and use this function.
11var pencil = {}
12pencil.writes() // It works
Thus adding any functionality to the prototype of any object gets available to all its instances hence sharing the same code for all instances. In order to add any functionality to objects’ prototype ( its die / blue print ). Javascript exposes an object through a member of Object also named as prototype which itself is an object. Therefore in the code above it is not necessary to call the function Object.getPrototypeOf(object) on any object but to use the prototype property which is available to all objects.
1// Adding functionality to built in Date object
2Date.prototype.showAlienDate = function () {
3 console.log('☺♂↓☺☻•☻')
4}
5var d1 = new Date()
6d1.showAlienDate() // it works
Not only you can enhance the functionality of built in object but also to any user defined object using its Constructor.
1//file-name:chap-02-02.js
2function Animal(itsName) {
3 this.name = itsName //public member
4}
5var rat = new Animal('Gerry')
6console.log(Animal.prototype) //
7
8// Adding methods to prototype
9Animal.prototype.move = function (steps) {
10 console.log('It has moved ' + steps + ' steps')
11}
By doing this we make sure that method moves get added to the prototype Animal and all instances can use it safely. Not to mention that there is nothing stopping you to add new properties to your object dynamically taking help from prototype object. Thus Animal.prototype.age = 0 ; will add a new property to an existing object.
It should be noted that when adding functions to prototype, it can be done safely in the following way only exposing the interface as shown below. This technique is know as revealing prototype pattern
1var OrganiteModel = function () {
2 this.shape = 'pyramid'
3 this.energyType = 'Scalar'
4 this.use = 'nonCommercial'
5}
6
7// Adding prototype
8OrganiteModel.prototype = (function () {
9 var on = function () {
10 console.log('It has been turned on')
11 }
12 var off = function () {
13 console.log('It is off!')
14 }
15 //return
16 return {
17 turnOrganiteOn: on,
18 turnOrganiteOff: off
19 }
20})()
21var myOrganite = new OrganiteModel()
22myOrganite.turnOrganiteOn() //It has been turned on
23myOrganite.turnOrganiteOff() //It is off!
Use of helper functions defined outside the constructor to access properties
It is possible to create any function outside the constructor which can access object properties. Since these functions live in global context can easily start to create problems with other functions. This situation is known as polluting the Global Namespace which may results eventually in conflicting with other names. Secondly, it violets the basic principle of encapsulation. Your object should provide its services not an outsider thus also regarded as anti pattern as shown below.
1 function Animal(itsName){
2 this.name = itsName; //public member
3 }
4 // new instance is created
5 var rat = new Animal("Gerry");
6 // function to access object properties
7 function showName(){
8 console.log(rat.name);
9 }
10 showName():
Methods defined in constructor
The above function can easily be defined inside the object constructor making it more safe from any possible conflicts and adhering to Object Oriented principles as follows.
1function Animal(itsName) {
2 this.name = itsName
3 this.showName = function () {
4 console.log(this.name)
5 }
6}
7var rat = new Animal('Gerry')
8rat.showName()
It should be noted that if a same function is added to the prototype ( name conflict) then only method defined on an object that is in constructor gets called. JavaScript will not throw an error if you use the same name as done in the constructor. A method is invoked on an object, it first look through its instance function list, if it finds it there, fine the instance function will be called . If it does not find there it will look into its prototype. See the example below
1function Foo() {
2 this.instanceFunction = function () {
3 console.log('This is an instance function')
4 }
5}
6//
7Foo.prototype.instanceFunction = function () {
8 console.log("This is a prototype's function")
9}
10new Foo().instanceFunction()
11//This is an instance function
The above always uses the instance function. If instance function was not there, it would look inside the prototype and call the prototype function.
1function Foo() {}
2//
3Foo.prototype.instanceFunction = function () {
4 console.log("This is a prototype's function")
5}
6new Foo().instanceFunction()
7// This is a prototype function.
The difference b/w function defined in constructor function and added using prototype
Both ways have some pros and cons which are not difficult to understand. When methods are initialized within the constructor function they become the part of the instance which is created using new operator.
Advantage of using methods within constructor
- They can take advantage of closures so that local variables declared becomes private and are only available to be manipulated by instance methods making data more secured. Being part of an object they avoid naming collision.
Disadvantage of using methods within constructor
- They are bound to create memory issues if number of instances increases. It gets very important specially when dealing with page load timing.
Advantage of using prototype approach
- They share same logic and data among all instances reducing the overhead of creating a method for each individual instance providing memory optimization. For example a factory makes toys the price of all toys are same but name and color may be different. Then using the price as an instance variable is an over head and can be safely put in the prototype so that it can be shared among all users.
1function LaserGadget(name, color) {
2 this.name = name
3 this.color = color
4}
5LaserGadget.prototype.price = 100
Disadvantage of using prototype approach
- They can not access local variables directly and there will be a slight overhead of searching the prototype chain. In order to access private variable an instance method can be called which returns the private variable as shown below.
1function Foo() {
2 var private = 10
3 this.getPrivateVaribale = function () {
4 return private
5 }
6}
7//
8Foo.prototype.accessPrivateVariable = function () {
9 console.log("This is a prototype's function " + this.getPrivateVaribale())
10}
11new Foo().accessPrivateVariable()
12// This is a prototype's function 10;
From above it should be clear that whether it is prototype function or simple value defined on a prototype. The first preference is given to instance members not prototype members. Thus a variable defined on both as done above using function will yield same result giving preference to instance variable rather than prototypal variable as shown below;
1function Thing(name) {
2 this.name = name
3}
4Thing.prototype.name = 'foo'
5var thing = new Thing('computer')
6console.log(thing.name) // computer
7delete thing.name // true
8console.log(thing.name) // foo
Hybrid Approach
The best way may be to use hybrid approach, it all depends upon the case and differ from one to another. If you take example of JQuery and look into the code you will find that methods are initialized within constructor while the other approach may be more suitable when the constructor object may need extending like in coffee script and
So far we have discussed creating objects with object literal, Object constructor and from user defined Constructor to create multiple instances from the prototype. There exist another way of creating object in JavaScript language known as creating with Factory function.
Constructor function can also be defined as function expression
To write the same constructor function as a function expression is also common among programmers. Both function declaration of a constructor function and function expression of a constructor function are correct with one already discussed difference of hoisting. They are also known as pseudo class
1var Animal = function (itsName) {
2 this.name = itsName
3 this.showName = function () {
4 console.log('This is ' + this.name)
5 }
6}
7
8var cat = new Animal('Timmy')
9cat.showName() //
Constructor function example from Metalsmith project
1function Metalsmith(directory) {
2 if (!(this instanceof Metalsmith)) return new Metalsmith(directory)
3 assert(directory, 'You must pass a working directory path.')
4 this.plugins = []
5 this.ignores = []
6 this.directory(directory)
7 this.metadata({})
8 this.source('src')
9 this.destination('build')
10 this.concurrency(Infinity)
11 this.clean(true)
12 this.frontmatter(true)
13}
The constructor makes sure that if new is forgotten it calls itself and assign two properties and then carry on invoking functions. But these functions are not declared so how it is possible to do this. Well this constructor takes help from inheritance. These functions are presumably inherited. If they are not inherited an error will be thrown.
They are added in prototype as shown below.
1 Metalsmith.prototype.directory = function(dirName){
2 if (! successful) return (some error or warning)
3 // use assertion
4 this._dirName = dirName;
5 return this;
6 }
Creating objects with factory functions
Factory function is a name given to a unique way of creating objects either from other objects in prototype based programming or from a class in class based programming. Factory pattern deals with the problem of creating objects without the need to specify the exact class of the object being created providing an abstraction to constructing objects.
The way they differ from constructor functions that they do not make use of a new operator because there are no constructor functions. The above Animal(itsName) constructor may be written in its simplest form as a factory function in a following way:
1//Factory function
2function Animal(itsName) {
3 // A new object created and referenced by that
4 var that = {
5 name: itsName,
6 isAlive: function () {
7 return breathes === true ? 'yes' : 'no'
8 },
9 showName: function () {
10 // console.log(name); error
11 console.log(that.name)
12 }
13 }
14 //private members not visible outside the function
15 var breathes = true
16 // returning object
17 return that
18}
19var dear = Animal('beauty')
20dear.isAlive() //yes
21dear.breathes //error breathes is private dear has no access to it
Note: -1.No use of
newoperator. -2.The object that can have any name. -3.Properties are accessed either by using object name and dot (.) notation or usingthis.
Similarly there is very clear distinction between private and public members. Variables defined outside the objects within the factory function are visible to the objects but not to the outside world. On the other hand object properties act as public members and used by the instances outside the function. Note inside the object’s member function the property name can not be accessed by its name.
It should also be noted that there is no need to return a named object, an unnamed object can also be returned as shown.
1function Animal(itsName) {
2 return {
3 name: itsName,
4 isAlive: function () {
5 return breathes === true ? 'yes' : 'no'
6 },
7 showName: function () {
8 // console.log(name); error
9 console.log(this.name)
10 }
11 } // un-named object return
12 //private members
13 var breathes = true
14}
Practical use of Factory Pattern
The factory pattern suggest defining an interface for creating an object where you allow the subclasses to decide which class to instantiate. This pattern handles the problem by defining a completely separate method for the creation of objects and which sub-classes are able to override so they can specify the ‘type’ of factory product that will be created. This is quite useful, in particular if the creation process involved is complex. You can often find factory methods in frameworks where the code for a library may need to create objects of particular types which may be sub-classed by scripts using the frameworks.
1function penFactory() {}
2penFactory.prototype.penClass = Pen
3penFactory.prototype.getPen = function (options) {
4 return new this.penClass(options)
5}
Anothe example of JavaScript Factory Function
1var Person = {
2 name: 'Person',
3 properties: {
4 firstName: {
5 range: 'NonEmptyString',
6 label: 'First name',
7 writable: true,
8 enumerable: true
9 },
10 lastName: {
11 range: 'NonEmptyString',
12 label: 'Last name',
13 writable: true,
14 enumerable: true
15 }
16 },
17 methods: {
18 getFullName: function () {
19 return this.firstName + ' ' + this.lastName
20 }
21 },
22 create: function (slots) {
23 // create object
24 var obj = Object.create(this.methods, this.properties)
25 // add special property for *direct type* of object
26 Object.defineProperty(obj, 'type', {
27 value: this,
28 writable: false,
29 enumerable: true
30 })
31 // initialize object
32 Object.keys(slots).forEach(function (prop) {
33 if (prop in this.properties) obj[prop] = slots[prop]
34 })
35 return obj
36 }
37}
Notice that the JS object Person actually represents a factory-based class. An instance of such a factory-based class is created by invoking its create method:
var pers1 = Person.create( {firstName:"Tom", lastName:"Smith"});
The method getFullName is invoked on the object pers1 of type Person by using the ‘dot notation’, like in the constructor-based approach:
console.log ("The full name of the person is: " + pers1.getFullName());
Notice that each property declaration for an object created with Object.create has to include the ‘descriptors’ writable: true and enumerable: true, as in lines 5 and 7 of the Person object definition above.
Advantage of Factory function over Constructor function
Creating Object with Object.create(prototype) method
When building is-a relation in JavaScript that is to create more specific object from generalized objects,the process is performed what is known as as prototyping. It is a process where one object is created using already defined object with the help of a function Object.create(prototype). A newly created object shares behaviour from not only its prototype but from the chain above, if it exist until a null is found.
This process also takes place implicitly when you create a singleton object using literal or using a Object() constructor whereby a new object is created with system provided prototype object which is already defined in, and placed as a property of the Object. This process is shown below to explain that both object are created from the same constructor internally and with the same prototype object.
1var obj1 = {}
2var obj2 = Object.create(Object.prototype)
3console.log(obj1.constructor === obj2.constructor) //true
4console.log(Object.getPrototypeOf(obj1) === Object.getPrototypeOf(obj2)) //true
5console.log(obj1.__proto__) // {}. Object.prototype
The above lines testifies that an object created with object literal is same as object created with the default prototype. The last line of code Obj1.__proto__ returns a prototype object. This internal property __proto__ is set to default prototype object when object is created.
Let’s see another example where a new object is created with another object as its prototype.
1var animal = { breathe: true } // A prototype object
2var rabbit = Object.create(animal)
3console.log(Object.getPrototypeOf(rabbit)) // { breathe:true}
4console.log(rabbit.__proto__) // {breathe: true}
5// creating another object and using __proto__ property
6var kangroo = {}
7kangroo.__proto__ = animal
8console.log(Object.getPrototypeOf(kangroo)) //{ breathe: true}
Before ECAMScript-5 Object.create() method, __proto__ property was used to point new objects’ prototype which can still be used. In above example rabbit was created from animal and animal by default have its prototype set to Object.prototype. Thus rabbit gets to share all the code from prototype chain. In order to stop inheriting the prototype chain, this property needs to point to a null object. This can be done directly or using ECMAScript-6 function. It is explained below.
1var animal = { breath: true }
2Object.setPrototypeOf(animal, null) // or animal.__proto__ = null;
3console.log(Object.getOwnPropertyNames(animal)) // [`breath`]
4console.log(Object.getPrototypeOf(animal)) // null
5var rabbit = Object.create(animal)
6console.log(rabbit.breath) // true. Inherited property
The use of property __proto__ is an old style when other methods were not available. The same result is achieved by using a static function defined on Object in ECMAScript-6, like many others Object.setPrototypeOf(obj,prototype).
Changing the prototype when working with constructor function
Not always we are dealing with a singleton object but types i.e., often with many instances of a same type. As learned before, constructor function provides a blue print for the required type to be created. Thus all item created from the constructor share the properties set in the constructor. If an object is created from the constructor function. This constructor provides the new object its identity or known as type and act like a class. Since in JavaScript there are no classes, they are regarded as pseudo classes, an achievement of duck typing. By default when a new object is created using a new operator from its constructor function, the returned object by default gets access to all members including variables and methods as well as share all services/code from the constructor function prototype, the default happens to be Object.prototype object. Let’s see the scenario explained below.
1function Animal(name) {
2 this.name = name
3}
4var rabbit = new Animal('Bunny')
5console.log(Object.getPrototypeOf(rabbit)) // Animal{}
6console.log(Object.getPrototypeOf(Object.getPrototypeOf(rabbit))) //{}. default
7console.log(Object.getOwnPropertyNames(rabbit)) // [`name`]
8// to get the inherited properties
9var allProp = []
10for (var o = rabbit; o !== null; o = Object.getPrototypeOf(o)) {
11 for (var name of Object.getOwnPropertyNames(o)) {
12 allProp.push(name)
13 }
14}
15console.log(JSON.stringify(allProp))
16/* ["name","constructor","hasOwnProperty","constructor","toString","toLocaleString","valueOf","isPrototypeOf","propertyIsEnumerable","__defineGetter__","__lookupGetter__","__defineSetter__","__lookupSetter__","__proto__"] */
17// Note if at this stage, Animal is augmented using its prototype property by adding any function or variable. That addition will show here.
To change the default prototype Object.setDefaultPrototype() can also be used to set it to null so that it no longer inherits services from the the default prototype automatically. One might get tempted to change it into a constructor function though it will work but it will be semantically wrong
1function Animal(name) {
2 this.name = name
3 Object.setPrototypeOf(this, null)
4}
5var rabbit = new Animal('Bunny')
6console.log(Object.getPrototypeOf(rabbit)) // null
The result above shows that rabbit has no prototype or in other words no class which is not right. What needs to be achieved is that this class does not share any code from its default prototype. This is done below using a property called prototype available to function object when created. This property was used earlier to add method or properties to a default Object.prototype. Now it can be used to set the prototype of this Object.prototype object __proto__ property to null stopping to inherit any more.
1function Animal(name) {
2 this.name = name
3}
4var rabbit = new Animal('Bunny')
5console.log(Object.getPrototypeOf(rabbit)) // Animal
6// Setting default prototype to null
7Animal.prototype.__proto__ = null
8console.log(Object.getPrototypeOf(Object.getPrototypeOf(rabbit))) //null
What is shown above requires understanding of JavaScript design and prototypal inheritance.
Prototypal Inheritance
In JavaScript there is no concept of one class extending another class. Inheritance which is one of the bases of Object Oriented Programming is implemented by a Prototypal inheritance. In JavaScript every object created is a type of Object and inherits some properties implicitly from Object.prototype object to share.
A user defined object can also use its inherited property __proto__ to extend another object.
1var animal = { eats: true }
2var kangroo = { jump: true }
3// kangroo is a kind of animal
4// extending animal
5kangroo.__proto__ = animal
6console.log(kangroo.eats) //true
When an object is a prototype of another object it inherits its’ (super object) properties. If the same property is also defined in the object which is inheriting the properties ( called derived objects )then its prototype is not checked. This process is of defining a same property in subclasses is known as overriding.
1var lameKangroo = { jump: false }
2lameKangroo.__proto__ = kangroo
3console.log(lameKangroo.jump) //false
If a property is not found in the derived object its prototype is checked if it is also not found there, it is assigned undefined type.
1var fish = { swims: true }
2fish.__proto__ = animal
3console.log(fish.hasLegs) // undefined
4var result = fish.hasLegs === undefined ? 'true' : 'false' // true
5var result = fish.hasLegs ? 'true' : 'false' // false
6//console.log("result = " + result);
It is a user responsibility to override the properties in subclass otherwise they may get assigned properties which many not be true.
1//add new property to super class
2animal.hasLegs = true
3console.log(fish.hasLegs) //true(?)
4//override `haslegs` property in fish class
5fish.hasLegs = false
6console.log(fish.hasLegs) //false
To avoid the ambiguity either designed the super class intelligently making no assumptions or override which is not true in derived class. A method can be added to objects in a same way
1//a method can be added to a class
2animal.moves = function moves(steps) {
3 console.log('I have walked ' + steps + ' steps')
4}
5kangroo.moves(2)
6fish.moves(3)
7//overriding moves in fish class
8fish.moves = function moves(meter) {
9 console.log('I have swam ' + meter + ' meters')
10}
11fish.moves(4)
12//similarly kangroo can override move method too
13kangroo.moves = function (jump) {
14 console.log('I have done ' + jump + ' jumps')
15}
16kangroo.moves(10)
1//
2var animal = {
3 hasmoved: false,
4 eats: true,
5 moves: function (steps) {
6 console.log('I have moved ' + steps + 'steps')
7 }
8}
9var kangroo = {
10 jumps: true,
11 moves: function (jump) {
12 console.log('I have done ' + jump + ' jumps')
13 this.hasmoved = true
14 }
15}
16var fish = {
17 swims: true,
18 moves: function (swim) {
19 console.log('I have swam ' + swim + ' meters')
20 this.hasmoved = true
21 }
22}
23kangroo.__proto__ = animal
24fish.__proto__ = animal
25kangroo.moves(2)
26console.log(kangroo.hasmoved) //true
27console.log(fish.hasmoved) //false
28fish.moves(10)
29console.log(fish.hasmvoed) // now true
The above code tells us that a property of a super class in not shared among derived classes every derived class gets its own set of properties which gets updated irrespective of others. Since properties belong to individual derived object reading the property this.prop or deleting the property delete.prop only effects the object referred by this key word.
Working with prototypes
- There is another way of working with prototypes objects that is creating an object from its prototype by using a function
Object.create(<prototype>). This is regarded as a standard way of creating a prototype object. The reason being that not all JavaScript engine supports__proto__property but all support this way of creating an object.Thus the above can be done in a following way
1var animal = {
2 eats: true,
3 hasmoved: false,
4 hasmoved: function () {}
5}
6kangroo = Object.create(animal)
7console.log(kangroo.eats) //true
8//adding properties to kangroo
9kangroo.jumps = true
10//to find out the prototype of any object use `getPrototypeOf(object)`
11console.log(Object.getPrototypeOf(kangroo)) //returns the base object
12//checking if kangroo is akind of animal
13var result = Object.getPrototypeOf(kangroo) === animal ? true : false
14console.log(result)
Creating object with class using ES6
- Classes in ES6 are not hoisted. Conventionally the name starts with a capital letter.
1class Point {
2 constructor(x, y) {
3 this.x = x
4 this.y = y
5 }
6}
- Unlike function class must be defined before they are to be used.
1const p1 = new Point(10, 20) // will throw an error
2
3class Point {}
4
5var square = new Rectangle(20, 20) // ok function declartion will be hoisted
6
7function Rectangle(width, height) {}
Class Expressions
- Another way of defining a class, it can be named or unnamed. If unnamed it can be found with its identifier name using
nameproperty. - Like functions it can be assigned to any identifier
1// unnamed
2let Rectangle = class {
3 constructor() {}
4}
5console.log(Rectangle.name) // Rectangle
6
7let Rectangle = class Rectangle1 {
8 constructor() {}
9}
10console.log(Rectangle.name) // Rectangle1
ES6 class body and methods
- Class fields / members such as
methods, constructorsare defined within curly brackets {}. - There can only be one constructor, it is to create and initialize and object created with a
classconstructs. - The key word
supercan be used to call the constructor of the parent class. - In class method can be defined without a keyword function.
- Both static fields and method can be defined in a class, they are only to be used by the class and not to be shared with instances.
- Classes can have both public and private properties.
- Public properties can be used by instances but private properties can only be used within the class.
- Public fields / properties are declared first just before the constructor.
- Private fields / properties are declared preceded with
#. They must be declared upfront and can not be declared
Sub classing
- A child or more specialized class is created by using the word
extendfrom its parent. - If a child class introduces a constructor it must call parent constructor first.
- If a child class over rides parent class method, it can first call parent method using
super.method()
1Class Animal{
2 constructor(name){
3 this.name = name;
4 }
5 speaks(){
6 console.log(`${this.name} does speak.`);
7 }
8}
9
10Class Rabbit extends Animal {
11 constructor(name){
12 super(name); // calls parent / super class constructor
13 }
14
15 // over riding parent method
16 speak(){
17 // can call super method super.speak()
18 console.log('${this.name} does not speak.');
19 }
20}
21
22let buny = new Animal('Buny');
23buny.speak(); // buny does not speak
Mix-ins
- Classes can not extend regular objects, to do so you must use
Object.setPrototypeOf()method.
1const Animal = {
2 speak(){
3 console.log("This is a normal object created with object literals");
4 }
5}
6class Dog {
7 constructor(name){
8 this.name = name;
9 }
10 speaks(){
11 console.log('${this.name} barks');
12 }
13}
14// Class Dog now inherits from Animal
15Object.setPrototypeOf(Dog.prototype,Animal);
16let d = new Dog('Mori');
17d.speaks(); // Mori barks
18``
19[//]: # ( End of this file)
20
21### Code used
22
23```javascript
24
25/**
26 * Autohor:Abdul Ghafoor Sayyed
27 * Date:04/11/2015
28 */
29//Creating different objects
30var empty = {}; //an empty object created with object litrels.
31var emptyWithNew = new Object(); //same as above but used new operator though not prefered
32var point = { x : 0, y : 0}; //an object with two properties note "=" sign is not used but ":""
33var anotherPoint = {x:point.x, y:poit.y}; //value of property itself is an expression ( complex)
34var line ={p1:point,p2:point}; //
35//o1 and o2 both inherits methods from Object.prototype
36
37o1.x = 1; //o1 object set its property name x and give value 1.
38
39var p = Object.create(o1); // A static method to create another object from a prototype
40p.x = 2; //p also set its property x , it does not change o1 property
41console.log(p.x , o1.x);
Above both ways do create an object but fails to provide a way to create same type of objects without repeating the code.
1var Dictionary = {
2 If: {
3 you: {
4 can: '',
5 make: ''
6 },
7 sense: ''
8 },
9 of: {
10 the: {
11 sentence: {
12 it: '',
13 worked: ''
14 }
15 }
16 }
17}
18
19function Iterate(obj) {
20 for (prop in obj) {
21 if (obj.hasOwnProperty(prop) && isNaN(prop)) {
22 console.log(prop + ': ' + obj[prop])
23 Iterate(obj[prop])
24 }
25 }
26}
27Iterate(Dictionary)















