Objects in JavaScript

JavaScript is an object oriented language but most people don't make use of the object oriented features of it except in passing. JavaScript uses a mixed object model in that it has some primitives as well as objects. JavaScript has five primitive types:

  • undefined
  • null
  • boolean
  • string
  • number

Of these five, only two are what we would expect to be an object anyway. The other three, boolean, string, and number all have wrapped versions, which are objects: Boolean, String, and Number. They are distinguished by starting with uppercase. This is the same sort of model used by Java, a hybrid of objects and primitives.

JavaScript will also box and unbox the primitives as needed.

In this code you can see the boxed and unboxed versions of JavaScript primitives at work:

var numberOne = new Number(1);
var numberTwo = 2;
typeof numberOne; //returns 'object'
typeof numberTwo; //returns 'number'
var numberThree = numberOne + numberTwo;
typeof numberThree; //returns 'number'

Creating objects in JavaScript is trivial. This can be seen in this code for creating an object in JavaScript:

var objectOne = {};
typeof objectOne; //returns 'object'
var objectTwo = new Object();
typeof objectTwo; //returns 'object'

Because JavaScript is a dynamic language, adding properties to objects is also quite easy. This can be done even after the object has been created. This code creates the object:

var objectOne = { value: 7 };
var objectTwo = {};
objectTwo.value = 7;

Objects contain both data and functionality. We've only seen the data part so far. Fortunately in JavaScript, functions are first class objects. Functions can be passed around and functions can be assigned to variables. Let's try adding some functions to the object we're creating in this code:

var functionObject = {};
functionObject.doThings = function() {
  console.log("hello world");
}
functionObject.doThings(); //writes "hello world" to the console

This syntax is a bit painful, building up objects an assignment at a time. Let's see if we can improve upon the syntax for creating objects:

var functionObject = {
  doThings: function() {
    console.log("hello world");
  }
}
functionObject.doThings();//writes "hello world" to the console

This syntax seems, at least to me, to be a much cleaner, more traditional way of building objects. Of course it is possible to mix data and functionality in an object in this fashion:

var functionObject = {
  greeting: "hello world",
  doThings: function() {
    console.log(this.greeting);
  }
}
functionObject.doThings();//prints hello world

There are a couple of things to note in this piece of code. The first is that the different items in the object are separated using a comma and not a semi-colon. Those coming from other languages such as C# or Java are likely to make this mistake.The next item of interest is that we need to make use of the this qualifier to address the greeting variable from within the doThings function. This would also be true if we had a number of functions within the object as shown here:

var functionObject = {
  greeting: "hello world",
  doThings: function() {
    console.log(this.greeting);
    this.doOtherThings();
  },
  doOtherThings: function() {
    console.log(this.greeting.split("").reverse().join(""));
  }
}
functionObject.doThings();//prints hello world then dlrow olleh

The this keyword behaves differently in JavaScript than you might expect coming from other C-syntax languages. this is bound to the owner of the function in which it is found. However, the owner of the function is sometimes not what you expect. In the preceding example this is bound to the functionObject object, however if the function were declared outside of an object this would refer to the global object. In certain circumstances, typically event handlers, this is rebound to the object firing the event.

Let's look at the following code:

var target = document.getElementById("someId");
target.addEventListener("click", function() {
  console.log(this);
}, false);

this takes on the value of target. Getting used to the value of this is, perhaps, one of the trickiest things in JavaScript.

ECMAScript-2015 introduces the let keyword which can replace the var keyword for declaring variables. let uses block level scoping which is the scoping you're likely to use from most languages. Let's see an example of how they differ:

for(var varScoped =0; varScoped <10; varScoped++)
{
  console.log(varScoped);
}
console.log(varScoped +10);
for(let letScoped =0; letScoped<10; letScoped++)
{
  console.log(letScoped);
}
console.log(letScoped+10);

With the var scoped version you can see that the variable lives on outside of the block. This is because behind the scenes the declaration of varScoped is hoisted to the beginning of the code block. With the let scoped version of the code letScoped is scoped just within the for loop so, once we leave the loop, letScoped is undefined. When given the option of using let or var we would tend to err on the side of always using let. There are some cases when you actually would want to use var scoping but they are few and far between.

We have built up a pretty complete model of how to build objects within JavaScript. However, objects are not the same thing as classes. Objects are instances of classes. If we want to create multiple instances of our functionObject object we're out of luck. Attempting to do so will result in an error. In the case of Node.js the error will be as follows:

let obj = new functionObject();
TypeError: object is not a function
  at repl:1:11
  at REPLServer.self.eval (repl.js:110:21)
  at repl.js:249:20
  at REPLServer.self.eval (repl.js:122:7)
  at Interface.<anonymous> (repl.js:239:12)
  at Interface.EventEmitter.emit (events.js:95:17)
  at Interface._onLine (readline.js:202:10)
  at Interface._line (readline.js:531:8)
  at Interface._ttyWrite (readline.js:760:14)
  at ReadStream.onkeypress (readline.js:99:10)

The stack trace here shows an error in a module called repl. This is the read-execute-print loop that is loaded by default when starting Node.js.

Each time that a new instance is required, the object must be reconstructed. To get around this we can define the object using a function as can be seen here:

let ThingDoer = function(){
  this.greeting = "hello world";
  this.doThings = function() {
    console.log(this.greeting);
    this.doOtherThings();
  };
  this.doOtherThings = function() {
    console.log(this.greeting.split("").reverse().join(""));
  };
}
let instance = new ThingDoer();
instance.doThings(); //prints hello world then dlrow olleh

This syntax allows for a constructor to be defined and for new objects to be created from this function. Constructors without return values are functions that are called as an object is created. In JavaScript the constructor actually returns the object created. You can even assign internal properties using the constructor by making them part of the initial function like so:

let ThingDoer = function(greeting){
  this.greeting = greeting;
  this.doThings = function() {
    console.log(this.greeting);
  };
}
let instance = new ThingDoer("hello universe");
instance.doThings();
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset