Built.io joins Software AG! Read all about the news.

Built.io Blog

10 Concepts Every Node.js Developer Should Know

,

JavaScript is a multi-paradigm language supporting many different styles of programming, like functional programming, procedural programming (like C) and object-oriented programming. It allows the developer to be flexible and take advantage of the various programming styles. Therefore, the developer community is quickly adopting Node.js as the new defacto standard for creating web applications or SaaS products. Many frameworks like expressJS, sailsJS and socketIO enable users to quickly bootstrap applications and focus only on the business logic.

JavaScript can be a boon if developed with care, or a bane if you are reckless. It does not have tail call optimization (which allows recursive functions to reuse stack frames for recursive calls). Without this, it's dangerous to use recursion for large iterations. Furthermore, Node.js being single threaded makes it imperative for developers to write asynchronous code. Multi-paradigm nature of Javascript is that it forces everything to be mutable. Probability of object and scope mutation should not be brushed aside while writing Node.js code.

As you get well-versed with Node.js, you may notice that there are many ways to solve one problem. But taking the right approach towards solving it is extremely critical. A wrong approach will result in multiple side effects like patchy or buggy applications or regressions to such an extent that force you to completely rewrite the entire logic. On the flip side, it can lay foundation for a robust, efficient and scalable application if the right approach is taken. Using structured rules, design patterns, concepts or basic rules of thumb will help you choose the most optimal approach for a problem. The following concepts will aid you in leveraging the power of Javascript language and writing efficient Node.js code:

1. Immediately-invoked function expression

It is a function that is executed as soon as it is created, not parsed. It has no connection with any events or asynchronous execution. You can define an IIFE as shown below:

            (function(){
          // all your code here
          // ...
      })();

The first pair of parentheses (function(){...}) converts the code inside the parentheses into an expression.The second pair of parentheses calls the function resulting from the expression. It can also be described as a self invoking anonymous function. Its most common usage is to limit scope of a variable made via var or to encapsulate context and avoid name collisions.

2. Closure

Closure is a javascript inner function that has access to its outer function's scope, even after the outer function has returned control. It makes a function have private variables. A simple example of a closure is shown below:

var count = (function () {
     var _counter = 0;
     return function () {return _counter += 1;}
})();
count();
count();
count();
// the counter is now 3

The variable count is assigned an outer function. The outer function only runs once, which sets the counter to zero and returns an inner function. The counter variable can only be accessed by the inner function, which makes it behave like a private variable.

3. Prototype

Every javascript function has a prototype property that is used to attach properties and methods. This property is not enumerable. It allows the developer to attach methods or member functions to its objects. Javascript supports inheritance only through the prototype property. In case of an inherited object, the prototype property points to the object’s parent. A common approach to attach methods to a function is shown below:

function Rectangle(x, y) {
    this._length = x;
    this._breadth = y;
}
Rectangle.prototype.getDimensions = function () {
    return { length : this._length, breadth : this._breadth };
};
Rectangle.prototype.setDimensions = function (len,bred) {
    this._length = len;
    this._breadth = bred;
};

4. Private properties, using closures

In Javascript, you can define private properties by using the underscore prefix as shown in the above example. However, this does not prevent a user from directly accessing or modifying a property that is supposed to be private.

Defining private properties using closures will help you solve this problem. The member functions that need access to private properties should be defined on the object itself. You can make private properties using closures as shown below:

function Rectangle(_length, _breadth) {
    this.getDimensions = function () {
        return { length : _length, breadth : _breadth };
    };
    this.setDimension = function (len,bred) {
        _length = len;
        _breadth = bred
    };
}

5. Module Pattern

Module pattern is the most frequently used design pattern in Javascript for achieving loosely coupled well-structured code. It allows to create public and private access levels. One way to achieve a module pattern is shown below:

var Direction = (function() {
  var _direction = 'forward'
  var changeDirection = function(d) {
    _direction = d;
  }
  return {
    setDirection: function(d) {
      changeDirection(d);
      console.log(_direction);
    }
  };
})();
Direction.setDirection('backward');       // Outputs: 'backward'
console.log(Direction._direction);

Revealing Module Pattern is similar to the Module pattern wherein the variables and methods that need to be exposed are returned in an object literal. The above example can be written using Revealing Module Pattern as:

var Direction = (function() {
  var _direction = 'forward';
  var _privateChangeDirection = function(d) {
    _direction = d;
  }
  return {
      setDirection: _privateChangeDirection
  };
})();

6. Hoisting

Javascript moves variables and function declarations to the top of their scope before code execution. This is called Hoisting. Regardless of the declaration of functions and variables, they are moved to the top of their scope.

Variable declarations are processed before any code is executed. Ironically, undeclared variables do not exist until they are assigned a value. This causes all undeclared variables to become global variables. Though function declarations are hoisted, Function expressions are not hoisted. JavaScript has an order of priority while hoisting variables and functions.

The priority is given below from higher to lower:

  • Variable assignment
  • Function declaration
  • Variable declarations

7. Currying

Currying is a method where you can pass all arguments that a function is expecting and get the result, or just pass a subset of arguments and receive a function back that’s waiting for the rest of the arguments. A simple example of a curry is given below:

var myFirstCurry = function(word) {
  return function(user) {
    return [word , ", " , user].join("");
  };
};
var HelloUser = myFirstCurry("Hello");
HelloUser("Rahul"); //"Hello, Rahul"

The original curried function can be called directly by passing each of the parameters in a separate set of parentheses one after the other as shown below:

     myFirstCurry("Hey, wassup!")("Rahul"); //"Hey, wassup!, Rahul"

8. Javascript Apply, Call and Bind Methods

It’s imperative that a JavaScript developer understands the difference between Call, apply and bind functions. All the three functions have one common similarity, their first argument is always the ‘this’ value, or context, that you want to give the function you are calling the method on.

1. Call

It is the easiest of all three. It's the same as invoking a function while specifying its context. Here’s an example:

var user = {
     name: "Rahul Mhatre",
     whatIsYourName: function() {
     console.log(this.name);
     }
};
user.whatIsYourName(); // Outputs: "Rahul Mhatre",
var user2 = {
     name: "Neha Sampat"
};
user.whatIsYourName.call(user2); // Outputs: "Neha Sampat"

2. Apply

It is the same as call, but the only difference is that you pass arguments as an array and not separately. Arrays are easier to manipulate in JavaScript, opening a larger number of possibilities for working with functions. Here is an example using apply and call:

var user = {
     greet: "Hello!",
     greetUser: function(userName) {
     console.log(this.greet + " " + userName);
     }
};
var greet1 = {
     greet: "Hola"
};
user.greetUser.call(greet1,"Rahul") // Outputs: Hola Rahul
user.greetUser.apply(greet1,["Rahul"]) // Outputs: Hola Rahul

3. Bind

This method allows you to pass arguments to a function without invoking it. A new function is returned with arguments bounded preceding any further arguments. Here is an example:

           var user = {
     greet: "Hello!",
     greetUser: function(userName) {
     console.log(this.greet + " " + userName);
     }
};
var greetHola = user.greetUser.bind({greet: "Hola"});
var greetBonjour = user.greetUser.bind({greet: "Bonjour" });
greetHola("Rahul") // Outputs: Hola Rahul 
greetBonjour("Rahul") // Outputs: Bonjour Rahul

9. Memoization

Memoization is an optimization technique used to speed up function executions by storing results of expensive operations and returning the cached results when the same set of inputs occur again. JavaScript objects behave like associative objects and arrays aid implementing memoization. We can convert a recursive factorial function into a memoized factorial function as shows below:

function memoizeFunction(func) {
  var cache = {};
  return function() {
    var key = arguments[0];
    if(cache[key]) {
      return cache[key];
    }
    else {
      var val = func.apply(this, arguments);
      cache[key] = val;
      return val;
    }
  };
}
var fibonacci = memoizeFunction(function(n) {
  return (n === 0 || n === 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
});

10. Method Overloading

Method overloading is a concept where a function can have the same name but different arguments. Compiler would determine which function to call based on the number of arguments passed. Method overloading is not directly possible in JavaScript. You can achieve it as shown below:

function overloadMethod(object, name, fn){
      if(!object._overload){
            object._overload = {};
      }
      if(!object._overload[name]){
            object._overload[name] = {};
      }
      if(!object._overload[name][fn.length]){
            object._overload[name][fn.length] = fn;
      }
        object[name] = function() {
          if(this._overload[name][arguments.length])
            return this._overload[name][arguments.length].apply(this, arguments);
        };
}
function Students(){
  overloadMethod(this, "find", function(){
    // Find a student by name
  });
  overloadMethod(this, "find", function(first, last){
    // Find a student by first and last name
  });
}
var students = new Students();
students.find(); // Finds all
students.find("Rahul"); // Finds students by name
students.find("Rahul", "Mhatre"); // Finds users by first and last name

Conclusion

Node.js is the future of web applications. V8 and JavaScript as the core, event-driven nature and out-of-the-box scalability pushes rapid development cycle, which are crucial in today's world. In my opinion, the 10 JavaScript concepts described in this article are the basic concepts any Node.js developer should know. But they are just the tip of the iceberg. Javascript is complicated, but yet powerful enough for developers to stop and take notice.The more you use it, the more you will understand how vast Javascript really is. Unearthing more knowledge about such a vast language will certainly help you avoid mistakes. I encourage everyone to learn more basic Javascript and basic Node.js. Get the basics right and you’ll see great results.

Want to learn more? Check out these related blog posts:

May the force be with you! - Star Wars

Popular Posts

Subscribe to our blog