Saturday, December 17, 2016

Functions in Javascript

The power and beauty of JS lies in the concept of functions. They are one of the two crucial aspects of the language (the other one being Objects). Though the language is flexible enough to suit many programming paradigms, it lends itself naturally to functional programming. Anyways, this will not be a post on functional programming rather an objective study of functions and its nuances. 
So jumping right in, functions in javascript are treated as value types. Coming from a Java background it was a drastic change and took some time to get used to that idea. 

  • Functions,
    • are first class objects - What does first class objects mean? In simple terms it means it can be passed around. Think of them as callable objects.
    • provide local scope - A var declared inside a function is visible/accessible anywhere within that function.

  • Functions can be used as plain functions, methods, constructor.
  • Functions that do not explicitly return a value return undefined.
  • Function statement vs Function expression
    • If the first token in a statement is ‘function’ then it is a function statement.
      • function foo() { }
    • Function expression can be 
      • named
        • var foo = function foo() { }
      • unnamed ( also known as anonymous function)
        • var foo = function() { }
  • Hoisting. A var declared anywhere within a function will be hoisted to the beginning/top of the function and initialized to undefined. The actual place where it is declared inside the function will be its assignment. Hoisting works with function statements as well but not expressions.
              var foo;

              // Outputs: undefined
              console.log(foo);

              foo = "Declared";
              // Outputs: "Declared"
              console.log(foo);
  • Function have 2 pseudo parameters:
    • arguments - An array like object (has a length property). This is a special parameter that a function gets along with the parameters it declares. Contains all arguments from the invocation.
    • this - It contains a reference to the object of invocation. Value bound at the time of invocation i.e. depends on the style of invocation :-
      • Function style -
        • foo() // value is either global object (ES3) or undefined (ES5)
      • Method style - 
        • obj.foo() // value is obj
      • Constructor style - 
        • new Foo() // A new object is created and returned
      • Call and apply style - All javascript functions have two methods, call and apply, which let you call functions and explicitly set the value of this
        • foo.apply(obj, args-array) // value is obj
        • foo.call(obj, arg1, arg2, arg3) // value is obj
  • Idea of functions started with Assembly language sub routines
  • In comparison to mathematical functions which never have any side effects, programming language functions usually need to have side effects to do interesting (UI) stuff.
  • Recursion is a powerful paradigm
  • Closure - This a topic which I would like to talk a little more by giving examples. It is only fair since it is such a deep and confusing one. To give you a sense of its complexity I want to mention a quote from the book YDKJS - "Understanding closures is like when Neo sees the Matrix for the first time". 
    • It is the context of an inner function that includes the scope of the outer function
    • An inner function enjoys that context even after the parent functions have returned.
    • So lets see why do we need them in the first place:
      • Global variables:
                     var names = ['zero', 'one', 'two'];
                     var digit_names = function(n){
                       return names[n]
                     };
                     console.log(digit_names(1)); // one
      • Here names is a global variable. What if there is another global variable in the environment? It is going to interfere with this one. To avoid this we can make the name array local to the digit_names function but that will slow things down since it will be created every time the function is called.
      • With closure:
                     var digit_name = (function(){
                         var names  = ['zero', 'one', 'two'];
                         return function(n){ return names[n] };
                     }()); // call immediately

                     console.log(digit_name(2)); // two      
      • Now digit_names will have the function returned which contains the names variable which is invoked only once, but the inner function which was returned will still have access to the names variable.
      • Another interesting thing to note here is this is not captured in closure. So, a common pattern to work around this is to assign this to a variable self/that.
      • Closures have a variety of other uses such as Partial application/curry-ing patterns, Promises, Sealer, Pseudo-classical inheritance, Prototypal inheritance, Module pattern etc.

    References:

    No comments:

    Post a Comment