728 x 90

Understanding the unusual parts of Javascript

Understanding the unusual parts of Javascript

Understanding the unusual parts of Javascript Javascript is a beautiful language that has a lot of misconceptions and this can lead to pulling out ones hairs in trying to debug errors we come across. This article will discuss  some of the unusual parts of JavaScript. JavaScript is prototype-based with first-class functions To understand this, first

Understanding the unusual parts of Javascript

Javascript is a beautiful language that has a lot of misconceptions and this can lead to pulling out ones hairs in trying to debug errors we come across. This article will discuss  some of the unusual parts of JavaScript.


JavaScript is prototype-based with first-class functions

To understand this, first understand what is Prototypal inheritance, In the prototypal inheritance form, objects inherit directly from other objects. In JS every object has a secret link to its parent object, thus whenever an object is asked for any property, it looks for it, if it does not have its parent will be asked then its parent, process will be continued till property is find or it will give an error.

For example

function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};

Circle.prototype.circumference = function () {         
    return 2 * Math.PI * this.radius;
};

var circle = new Circle(5);
var circle2 = new Circle(10);

circle.area() // 78.53981633974483
circle.diameter() // Uncaught TypeError: circle2.diameter is not a function

Here radius is a Number which also inherits properties from Number thats why it outputs "5" on circle.radius.toString()

By first-class functions, it meant that function can be stored in variables and then can be passed around.

It also supports High Order Functions, it means function can take other function as input and return a function as output.

Making it a multi-paradigm language, supporting object-oriented, imperative, and functional programming styles.

Multi-paradigm means, you can program in with various coding styles like OOP or Functional or mix of both.

It has an API for working with text, arrays, dates and regular expressions, but does not include any I/O, such as networking, storage, or graphics facilities, relying for these upon the host environment in which it is embedded.

JS have API for text, arrays etc, this mean JS can count elements in an array or can pop something out from it but it can’t perform an API call itself, yes you read it right JS Engine doesn’t do it, browser does.

How JavaScript Works

Let’s see how things work under the hood.

Javascript is single threaded, it means it can execute one thing at a time, check the figure given below, whenever there some operation like console.log or a + b it pushes it into the stack operates it and pop it out.

Understanding the unusual parts of Javascript

1. Constructor Functions

Since Javascript is a functional programming language where everything is just a function, in order to have a class like (creating a blueprint for the objects to be created) functionality in javascript, constructor functions are used, lets see how constructor functions work:

function Vehicle(make, model, color) {
        this.make = make,
        this.model = model,
        this.color = color,
        this.getName = function () {
            return this.make + " " + this.model;
        }
}

The function above provides almost similar functionality as that of a Java class, in order to create an object of type Vehicle, we do following:

let car = new Vehicle("Toyota", "Corolla", "Black");
let car2 = new Vehicle("Honda", "Civic", "White");

This is perfect. isn’t it? now, we can create as many objects of type Vehicle as we want by just writing one line code.

But wait, there are a few problems with this technique.

When we write new Vehicle(), what Javascript engine does under the hood is that it makes a copy of our Vehicle constructor function for each of our objects, each and every property and method is copied to the new instance of the Vehicle, that’s okay, what is the problem in this?!

The problem here is that we don’t want the member functions (methods) of our constructor function to be repeated in every object. That is redundant. Isn’t it? Another problem is that we can’t add a new property or method to an existing object like this:

car2.year = "2012"

To add this year property you will have to add it to the constructor function itself:

function Vehicle(make, model, color, year) {
        this.make = make,
        this.model = model,
        this.color = color,
        this.year = year,
        this.getName = function () {
            return this.make + " " + this.model;
        }
}

2. Prototype

Whenever a new function is created in javascript, Javascript engine by default adds a prototype property to it, this property is an object and we call it “prototype object”. By default this prototype object has a constructor property which points back to our function, and another property __proto__ which is an object, have a look at the following:

The __proto__ property is called dunder proto, and it points to the prototype property of our constructor function.

“word dunder comes from python, where variable names bracketed with double underscores are called dunder properties”

Whenever a new instance of the constructor function is created this property is also copied to the instance along with other properties and methods:

Now, this prototype object can be used to add new properties and methods to the constructor function using the following syntax and they will be available to all the instances of the constructor function:

car.prototype.year = "2016";

Prototype is cool, but there are a few things you need to be careful while using prototype approach. Prototype properties and methods are shared between all the instances of the constructor function, but when any one of the instances of a constructor function makes any change in any primitive property, it will only be reflected in that instance and not among all the instances:

Another thing is that reference type properties are always shared among all the instances, for example, a property of type array, if modified by one instance of the constructor function will be modified for all the instances:

There is a very interesting and more detailed article on prototype here.


3. Classes

We understand the constructor functions and prototype, now its easy to understand the class, why? because javascript classes are nothing but just a new way of writing the constructor functions by utilizing the power of prototype, lets see an example for this:

class Vehicle {
    constructor(make, model, color) {
        this.make = make;
        this.model = model;
        this.color = color;
    }

    getName() {
        return this.make + " " + this.model;
    }
}

And in order to create a new instance of class Vehicle, we do this:

let car = new Vehicle("Toyota", "Corolla", "Black");

So if you compare this with what we did in the beginning while explaining the constructor functions, it is very similar.

By writing the above code, we have actually created a variable named Vehicle which references to function constructor defined in the class, also we have added a method to the prototype of the variable Vehicle, same as bellow:

function Vehicle(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
}

Vehicle.prototype.getName()= function () {
    return this.make + " " + this.model;
}

let car = new Vehicle("Toyota", "Corolla", "Black");

So, this proves that class is a new way of doing the constructor functions. Yes, but there are few new things introduced and some rules set in order to make it more like actual classes.

1. constructor requires new keyword to work. It means constructor will only be called when we do following.

let car = new Vehicle("Toyota", "Corolla", "Black");

But in constructor functions we could actually do this:

This happens if you try to instantiate a class variable like above:

2. Class methods are non-enumerable. In javascript each property of an object has enumerable flag, which defines its availability for some operations to be performed on that property. A class sets this flag to false for all the methods defined on its prototype.

3. If you don’t add a constructor to a class, a default empty constructor will be added automatically. Same as the following:

constructor() {}

4. Code inside a class is always in strict mode, this helps to write error free code, by throwing errors, on mis typings, or syntactical errors done while writing code, or even removing some code by mistake, which is referenced from somewhere else.

5. Class declarations are not hoisted. Hoisting in javascript is behavior in which all the declarations are automatically moved on top of the current scope, this behavior actually lets you use a variable or a function before its declared.

So Class declarations are not hoisted means, you can’t use a class before it is declared, it will return not defined error, see below:

This works:

But this doesn’t:

6. Classes doesn’t allow the property value assignments like constructor functions or object literals. You can only have functions or getters / setters. So no property:value assignments directly in the class.


4. Class Features

1. Constructor

Constructor is special function in the class declaration, which defines a function, that represents the class itself. When you new up a class instance, the constructor is automatically called.

let car = new Vehicle("Honda", "Accord", "Purple");

A constructor can use super keyword to call the constructor of the class its extending from.

A class can not have more than 1 constructor function.

2. Static Methods

Static methods are functions on class itself, and not on its prototype, unlike the other methods in the class, which are defined on its prototype.

Static methods are declared using static keyword, and are mostly used to create utility functions. They are called without creating the instance of the class. See an example below.

class Vehicle {
    constructor(make, model, color) {
        this.make = make;
        this.model = model;
        this.color = color;
    }

    getName() {
        return this.make + " " + this.model;
    }

    static getColor(v) {
        return v.color;
    }
}

let car = new Vehicle("Honda", "Accord", "Purple");

Vehicle.getColor(car); // "purple"

Remember, static methods can not be called from the class instance.

3. Getters/Setters

Class can also have getter/setters to get the property value and or to set the property values. Something like below.

class Vehicle {
    constructor(model) {
        this.model = model;
    }
    
    get model() {
        return this._model;
    }

    set model(value) {
        this._model = value;
    }
}

Under the hood, getters/setters are defined on the class prototype.

4. Subclassing

Subclassing is a way you can implement inheritance in Javascript classes, keyword extends is used to create a child class of a class.

Lets take an example:

class Vehicle {
    constructor(make, model, color) {
        this.make = make;
        this.model = model;
        this.color = color;
    }

    getName() {
        return this.make + " " + this.model;
    }
}

class Car extends Vehicle{
    getName(){
        return this.make + " " + this.model +" in child class.";
    }
}

let car = new Car("Honda", "Accord", "Purple");

car.getName(); // "Honda Accord in child class."

You can see when calling the getName() function, the function from the child class was called.

Sometimes we need to call function of the base class. We use super keyword in order to call the base class methods from within the methods of the child class.

Change the getName() function in the child class to something like:

class Car extends Vehicle{
    getName(){
        return super.getName() +"  - called base class function from child class.";
    }
}

Now, if you call getName() from the instance it should return the result as below:

3. Closures

A closure is an inner function that has access to the outer (enclosing) function’s variables—scope chain. The closure has three scope chains: it has access to its own scope (variables defined between its curly brackets), it has access to the outer function’s variables, and it has access to the global variables.

The inner function has access not only to the outer function’s variables, but also to the outer function’s parameters. Note that the inner function cannot call the outer function’s arguments object, however, even though it can call the outer function’s parameters directly.

You create a closure by adding a function inside another function.
A Basic Example of Closures in JavaScript:

 

function showName (firstName, lastName) {

var nameIntro = "Your name is ";
    // this inner function has access to the outer function's variables, including the parameter
function makeFullName () {
        
return nameIntro + firstName + " " + lastName;
    
}

return makeFullName ();

}


showName ("Michael", "Jackson"); // Your name is Michael Jackson


 

Closures’ Rules and Side Effects

  1. Closures have access to the outer function’s variable even after the outer function returns:
    One of the most important and ticklish features with closures is that the inner function still has access to the outer function’s variables even after the outer function has returned. Yep, you read that correctly. When functions in JavaScript execute, they use the same scope chain that was in effect when they were created. This means that even after the outer function has returned, the inner function still has access to the outer function’s variables. Therefore, you can call the inner function later in your program. This example demonstrates:

    function celebrityName (firstName) {
        var nameIntro = "This celebrity is ";
        // this inner function has access to the outer function's variables, including the parameter
       function lastName (theLastName) {
            return nameIntro + firstName + " " + theLastName;
        }
        return lastName;
    }
    
    var mjName = celebrityName ("Michael"); // At this juncture, the celebrityName outer function has returned.
    
    // The closure (lastName) is called here after the outer function has returned above
    // Yet, the closure still has access to the outer function's variables and parameter
    mjName ("Jackson"); // This celebrity is Michael Jackson

  2. Closures store references to the outer function’s variables; they do not store the actual value. 
Closures get more interesting when the value of the outer function’s variable changes before the closure is called. And this powerful feature can be harnessed in creative ways, such as this private variables example first demonstrated by Douglas Crockford:
    function celebrityID () {
        var celebrityID = 999;
        // We are returning an object with some inner functions
        // All the inner functions have access to the outer function's variables
        return {
            getID: function ()  {
                // This inner function will return the UPDATED celebrityID variable
                // It will return the current value of celebrityID, even after the changeTheID function changes it
              return celebrityID;
            },
            setID: function (theNewID)  {
                // This inner function will change the outer function's variable anytime
                celebrityID = theNewID;
            }
        }
    
    }
    
    var mjID = celebrityID (); // At this juncture, the celebrityID outer function has returned.
    mjID.getID(); // 999
    mjID.setID(567); // Changes the outer function's variable
    mjID.getID(); // 567: It returns the updated celebrityId variable

  3. Closures Gone Awry
    Because closures have access to the updated values of the outer function’s variables, they can also lead to bugs when the outer function’s variable changes with a for loop. Thus:

    // This example is explained in detail below (just after this code box).
    function celebrityIDCreator (theCelebrities) {
        var i;
        var uniqueID = 100;
        for (i = 0; i < theCelebrities.length; i++) {
          theCelebrities[i]["id"] = function ()  {
            return uniqueID + i;
          }
        }
        
        return theCelebrities;
    }
    
    var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
    
    var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
    
    var stalloneID = createIdForActionCelebs [0];

console.log(stalloneID.id()); // 103

    In the preceding example, by the time the anonymous functions are called, the value of i is 3 (the length of the array and then it increments). The number 3 was added to the uniqueID to create 103 for ALL the celebritiesID. So every position in the returned array get id = 103, instead of the intended 100, 101, 102.

    The reason this happened was because, as we have discussed in the previous example, the closure (the anonymous function in this example) has access to the outer function’s variables by reference, not by value. So just as the previous example showed that we can access the updated variable with the closure, this example similarly accessed the i variable when it was changed, since the outer function runs the entire for loop and returns the last value of i, which is 103.

    To fix this side effect (bug) in closures, you can use an Immediately Invoked Function Expression (IIFE), such as the following:

    function celebrityIDCreator (theCelebrities) {
        var i;
        var uniqueID = 100;
        for (i = 0; i < theCelebrities.length; i++) {
            theCelebrities[i]["id"] = function (j)  { // the j parametric variable is the i passed in on invocation of this IIFE
                return function () {
                    return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array
                } () // BY adding () at the end of this function, we are executing it immediately and returning just the value of uniqueID + j, instead of returning a function.
            } (i); // immediately invoke the function passing the i variable as a parameter
        }
    
        return theCelebrities;
    }
    
    var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
    
    var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
    
    var stalloneID = createIdForActionCelebs [0];
    
console.log(stalloneID.id); // 100
    
    var cruiseID = createIdForActionCelebs [1];
console.log(cruiseID.id); // 101

 

So, we tried to explain unusual parts of javaScript and in the end we learnt about some of the Javascript features.

You can continue reading through the following awesome articles written by Javascript geeks out there, not only this, there are tons of other articles available on the internet, that can help you grab the idea behind the topic.

References:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
  2. http://2ality.com/2015/02/es6-classes-final.html
  3. https://javascript.info/class
  4. https://thejsguy.com/tutorials/javascript-constructor-functions-and-classes
  5. https://www.phpied.com/3-ways-to-define-a-javascript-class/

earthboxx
ADMINISTRATOR
PROFILE

Posts Carousel

Leave a Comment

Your email address will not be published. Required fields are marked with *

Cancel reply