Sage-Code Laboratory
index<--

JavaScript Objects

JavaScript objects are composite variables that encapsulate multiple values and methods. Each value is represented by a different element that has a name and is called "object attribute" or "field". Objects can also contain functions. These functions are called in objec oriented design: "methods" but in JavaScript they are simple functions that happen to be defined into an object context.

Object Literal

Object literals are using a specific notation invented for JavaScript that is called: "JSON = "Java Script Object Notation". This notation is nice and slim so it was adopted by many other programming languages as a data format.

A simplified version of JSON has become standard for storing objects in text files or sending objects over the network. It is considered a light weight data representation format. It can not transport functions though.

Example:

let person = {
   firstName : "John",
   lastName : "Doe",
   age : 50,
   eyeColor : "blue",
   fullName : function () {
      return this.firstName + " " + this.lastName
   }
};

In this example we declare an object: person that has several properties and one method. A method is a property of type function. The method name in this example is fullName.

Observe:

Object Members

You can access object members in two ways:

You access an object method with the following syntax:

Inside methods you access properties of object using "this" keyword:

Alert: We can assign a function to a variable by mistake. Therefore do not forget to use parentheses () for a function call. Otherwise you can assign the function itself ! The empty parenthesis have the role to execute the function and are required even if there is no parameter for function.

Example:

console.log(person.firstName); // John
console.log(person.lastName); // Doe
console.log(person.fullName());// John Doe

Empty Object

You can create an empty object using syntax:

// create empty object
const objectName = {};
// add properties
objectName.x = 10;
objectName.y = 20;

Note:  This is just a demo, in practice you should not use this method to create objects. The code looks messy and is considered bad practice.

Object Factory

An object factory is a normal function that create an object. This kind of function is no longer used in practice but in older JavaScript code. It is good to know about this so you can read older code:

/* object factory function */
function createNewPerson(name) {
   var obj = {};
   obj.name = name;
   obj.greeting = function() {
      console.log('Hi! I\'m ' + obj.name + '.');
   };
   return obj;
}
/* create new objects */
var johnPerson = createNewPerson("John");
var petruPerson = createNewPerson("Petru");
johnPerson.greeting(); //call object method
petruPerson.greeting(); //call object method

Object Constructor

This is a special function that can produce an object, using keyword "new". This function is more elegant than "object factory". Does not have return, and is used only to create object instances.

Example:

/* object constructor */
function Person(name) {
   this.name = name;
   this.greetings = function() {
   console.log('Hi! I\'m ' + this.name + '.');
 };
};
// instantiate two objects
var john = new Person("John");
var petru = new Person("Petru");
john.greetings(); // Hi! I'm John
petru.greetings();// Hi! I'm Petru

Fundamental Object

JavaScript has predefined objects. One of these is the "Fundamental Object". There are two alternative methods to create objects using the fundamental object:

Example:

// equivalent to "var o = {}";
let o = new Object();
// equivalent to "b = new Boolean()";
let b = new Object(Boolean()); 

Object prototype

Object.create() method can be used to create new object from an existing object. The new object is based on "object prototype". An object prototype is automatically created when you create the object.

By reusing a prototype you inherit all its methods. This is how inheritance works in JavaScript. Therefore JavaScript is a Prototype Oriented Language. You can access the prototype using dot notation and you can extend the prototype with new functions and properties.

Example:

// object constructor Shape:
function Shape() {
   this.name = 'Shape';
}
// object constructor Rectangle:
function Rectangle() {
/* Using JavaScript special function call(),
   an object can use a method belonging to another object */
   Shape.call(this);
}
// binding prototype, to realize the inheritance
Rectangle.prototype = Object.create(Shape.prototype);
// test inheritance
const rect = new Rectangle();
console.log(rect.name); // expected output: "Shape"

How to modify prototype

The prototype of an object can be modified. You can add new functions and properties to a prototype using dot notation. When you do, all instances of the prototype will receive the new members.

/* define constructor for Person */
function Person(name) {
// property and method definitions
   this.name = name;
// public method: hello
   this.hello = function() {
   console.log("hello " + this.name);
 }
};
/* create an object */
let person = new Person('Smith');
/* extend Person with a new function */
Person.prototype.farewell = function() {
   console.log("By "+ this.name );
};
person.hello(); // test internal method
person.farewell();// test external method

Function Object

Every JavaScript function is actually a Function object. It can be created with alternative notation:

/* alternative notation for function object */
let sum = new Function('a', 'b', 'return a + b');
console.log(sum(2, 6)); // expected output: 8

Note: The example above is only to prove a point. It is not used in practice. The point is: if a function is an object than it can have properties. It means you can create new properties for a function using dot notation. Function properties

Having a property for a function is similar to a static variable. It can take values that are visible from outside the function and can be modified to modify the function behavior.

Example:

/* function with static property */
function getNext() {
    if (getNext.next == undefined) {
       getNext.next = 0;
    } 
    else {
       getNext.next++;
    }
    return getNext.next;
}
/* test static property */
console.log(getNext()); // 0
console.log(getNext()); // 1
getNext.next = 8
console.log(getNext()); // 8
getNext.next = 12
console.log(getNext()); // 13

Observe: You must use: function.property to define function properties. They are attached to function itself not to an object. You can not use this.property to define function properties. That is the difference.

Define "class"

Is your head spinning yet? Sorry, this prototype theory prove to be difficult to grasp and sometimes insufficient.Therefore JavaScript try to evolve and has introduced new concept of "class". This is an attempt to adopt Java style OOP. In fact a "class" is syntax sugar for constructor function. It can be used to create object instances using keyword: "new".

Syntax:

class MyClass {
 property_name = value; // class property
 constructor(...) { // constructor has always this name
 // ...
 }
 method_name(...) {} // class method
 second_method(...) {} // class method
 get something(...) {} // getter method
 set something(...) {} // setter method
}

Example:

In this example you can see 2 classes. One is extending the other. This is how inheritance can be done using the new JavaScript notation.

// base class
class Polygon {
   constructor(width, height) {
       this.name = "Polygon";
       this.width = width;
       this.height = height;
   }
}
// instantiate object: polygon
let polygon = new Polygon(20,30);
console.log(polygon.name); // "Polygon"

// create a child class
class Square extends Polygon {
   constructor(length) {
       /* call constructor 
          of the parent class 
          this is a mandatory call */
       super(length, length);
       /* set initial value */
       this.name = 'Square';
   }
   
   // read-only property
   get area() {
       return this.height * this.width;
   }
};

// test new class: Square
let square = new Square(20);
console.log(square.name); // Square
console.log(square.area); // 400
square.area = 50; // no effect
console.log(square.area); // 400

Notes:

Object destructuring

You can use destructuring assignment with object literals. This is especially interesting when a function return multiple results that need to be assigned to different variables. Deconstructor will read attrubutes by name and will distribute them into independent variables.JavaScript is weard when it does this. If you are not aware you will not understand the code.

Example:

/* declare and initialize object */
let obj = {a: 42, b: true, c:"test"};
/* partial deconstructing object */
let {a, c} = obj;
console.log(a); // 42
console.log(c); // test
/* partial decosntructing one attribute */
let {b} = obj;
console.log(b); // true
Observe: Object deconstruction is very different than array deconstruction. It works by name not by position. In the example above, attribute "b: is not captured into a variable but skipped. We read only attribues "a" and "c". Therefore c == "test". In the end we read also "b" using deconstion.

Example:

/* object with 2 attributes */
let o = {p: 42, q: true};
/* mapping attributes */
let {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true

Note: There is more to know about destructuring objects:
Read mozila documentation for details:MDN Destructuring

JavaScript Exceptions

Exceptions are abnormal situations that can cause a computer program to malfunction, produce unpredictable or incorrect results.In this case the application should report an error message and interrupt itself or at least verify the situation and decide to stop or continue.

Producing exceptions

An exception can be created by the system when a statement can not be executed properly. You can also create exceptions on purpose. Usually you check a condition and decide before producing an exception. Most elegant is to produce an Error object as exception, but JavaScript enable you to produce an exception using any value. The example below will use keyword: throw to create an exception.

Example:

// create exception object
throw new Error("You got an exception")
// create exception with a string object
throw "You get an exception!"
// create exception with a number object
throw -1

Homework: Run the example above. This example will stop on first statement, but you can comment statements one by one to check the effect of each individual case. The script will stop and you get an error message similar to this:

error: Uncaught -1

Resolving exceptions

Unresolved exceptions cause script to stop and produce an error to console, but your web-page will usually continue working with defects. To avoid these defects you must do proactive programming. This means you must check conditions and handle errors to avoid "Uncaught Exceptions".

For resolving exception you can use a special "control flow" statement that is called "try". It is a multi-block statement with several regions: The main block start after "try" keyword. You can use "catch blocks" to resolve several potential errors and "finally" block to execute after error is resolved.

Example:

try {
   throw 'error';
}
catch (e) {
   console.error(e);
}
finally {
   console.log('done')
}

Notes:

If you use: console.error() instead of console.log, the console will probably print your error message with red color. You can use a function to do something with the error. Usually you log the error and continue program execution. Handler

The catch statement has a handler that is created automatically. You can specify this handler name in parenthesis after catch keyword. In our case the exception handler is: e. Handler type depends on your throw statement. If you create an Error object the handler will represent the object. In our case, e is of type 'string'.

Conditional Catch

You can create different catch statements using a conditional. Notice though this is very new and it may bot be supported by many engines. Check with your team before you use this syntax.

Pattern:

Next is "pseudo code" fragment to demonstrate "conditional catch" design pattern.

try {
   myroutine(); // may throw three types of exceptions
} catch (e if e instanceof TypeError) {
 // statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
 // statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
 // statements to handle EvalError exceptions
} catch (e) {
 // statements to handle any unspecified exceptions
 logMyErrors(e); // pass exception object to error handler
}

Finally Block

The finally block is executed no matter what. In this block you can close a resource or log a message. When in this block you do not know if there was an error or not, but this code is guaranteed to be executed in any case.

Pattern:

Next pattern demonstrate how to handle resources using try – finally block.

open_resource();
try {
   use_resource(my_data);
}
finally {
   close_resource(); // always close the resource
}

JavaScript Error

The Error instance must be created using "new" operator like any other object. You can create an exception object and "throw" the object later once or several times, depending on your programming logic. Also you can create the object anonymously and give it a name later using "catch".

Example:

// named exception
let exception = new Error('my exception');
// create a named exception
try {
   throw exception
}
catch (e) {
   if (e instanceof Error) {
      console.error(e.message);
   } else {
      console.log("unexpected exception");
   }
}
// your program can continue
console.log("continue program")

To learn more about Error object read the reference:  MDN Error


Caution: Next example demonstrate a common error in JavaScript: Using relation operators with two objects will compare object references and not object attributes or values they represent. Read the example and wander how is this possible. JavaScript is not perfect and sometimes difficult to explain.
/* create non null Boolean object */
var a = Boolean(false); // boolean
var b = new Boolean(false); // object
console.log(a === false) //true (expected)
console.log(b === false) //false (unexpected)
// a is "boolean" works as expected
if (a)
 console.log("a is true");
else
 console.log("a is false"); //expected
// b is "object" works in unexpected way
if (b)
 console.log("b is true"); // unexpected
else
 console.log("b is false");

Read next: Collections