Better Javascript

Contents

  • Functions
  • Defining
  • function expression
  • function scope
  • nested functions
  • Closures
  • Arguments
  • Parameters
  • constructor vs declaration vs expression
  • call vs apply vs bind
  • Module Pattern

Functions

  • JavaScript procedure—a set of statements that performs a task or calculates a value
  • To use a function, you must define it somewhere in the scope from which you wish to call it
  • function is composed of a sequence of statements called the function body. Values can be passed to a function, and the function will return a value.

  • The Function constructor creates a new Function object. In JavaScript every function is actually a Function object.

Defining Functions

 

A function definition (also called a function declaration, or function statement) consists of the function keyword, followed by:

  • The name of the function.
  • A list of arguments to the function, enclosed in parentheses and separated by commas.
  • The JavaScript statements that define the function, enclosed in curly brackets, { }.
function square(number) {
  return number * number;
}

Function Expressions

 

functions can also be created by a function expression. Such a function can be anonymous;

var factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1); };

console.log(factorial(3));

_______________________________________________________

function map(f, a) {
  var result = [], // Create a new Array
      i;
  for (i = 0; i != a.length; i++)
    result[i] = f(a[i]);
  return result;
}

var multiply = function(x) { return x * x * x; }; // Expression function.
map(multiply, [0, 1, 2, 5, 10]);

Function scope

a function defined in the global scope can access all variables defined in the global scope. A function defined inside another function can also access all variables defined in its parent function and any other variable to which the parent function has access.

// The following variables are defined in the global scope
var num1 = 20, num2 = 3, name = 'Chamahk';

// This function is defined in the global scope
function multiply() {
  return num1 * num2;
}

multiply(); // Returns 60

// A nested function example
function getScore() {
  var num1 = 2, num2 = 3;
  
  function add() {
    return name + ' scored ' + (num1 + num2);
  }
  
  return add();
}
getScore(); // Returns "Chamahk scored 5"

Nested Functions

  • You can nest a function within a function. The nested (inner) function is private to its containing (outer) function.
  • the inner function contains the scope of the outer function.
  • The inner function can be accessed only from statements in the outer function.
  • The inner function forms a closure: the inner function can use the arguments and variables of the outer function, while the outer function cannot use the arguments and variables of the inner function.
function addSquares(a, b) {
  function square(x) {
    return x * x;
  }
  return square(a) + square(b);
}

a = addSquares(2, 3); // returns 13

b = addSquares(3, 4); // returns 25

Closures

  • a persistent local variable scope which holds on to local variables even after the code execution has moved out of that block.
  • A closure is created when the inner function is somehow made available to any scope outside the outer function.
var createPet = function() {
  var name;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    }
    
  }
}

var pet = createPet('Vivie');
pet.getName();                  // Vivie
pet.setName('Oliver');

Closures...

  • Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure ‘remembers’ the environment in which it was created.
  • The inner variables of the inner functions act as safe stores for the outer arguments and variables.
  • They hold "persistent", yet secure, data for the inner functions to work with.
var getCode = (function() {
  var secureCode = '0]Eal(eh&2';    
  // A code we do not want outsiders to be able to modify...
  
  return function() {
    return secureCode;
  };
}());

getCode();    // Returns the secureCode

Arguments

  • The arguments of a function are maintained in an array-like object
  • Using the arguments object, you can call a function with more arguments than it is formally declared to accept.
  • useful if you don't know in advance how many arguments will be passed to the function.
function myConcat(separator) {
   var result = ''; // initialize list
   var i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}

// returns "red, orange, blue, "
myConcat(', ', 'red', 'orange', 'blue');

// returns "elephant; giraffe; lion; cheetah; "
myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');

Parameters

1. Default params

- parameters of functions default to undefined

function multiply(a, b) {
  b = typeof b !== 'undefined' ?  b : 1;

  return a * b;
}
multiply(5); // 5

// New syntax
function multiply(a, b = 1) {
  return a * b;
}
multiply(5); // 5

2. Rest params
- syntax allows us to represent an indefinite number of arguments as an array

function multiply(multiplier, ...theArgs) {
  return theArgs.map(function(x) { return multiplier * x});
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]

constructor vs. declaration vs. expression

// Function Constructor
var multiply = new Function('x', 'y', 'return x * y');

// function declaration
function multiply(x, y) {
   return x * y;
} // there is no semicolon here

// function expression of an anonymous function assigned to multiply
var multiply = function(x, y) {
   return x * y;
};

var multiply = function func_name(x, y) {
   return x * y;
};

// Difference
var y = function x() {};
alert(x); // throws an error

call

function sayHello(firstName, secondName) {
    console.log(`${this.sayHello()} ${firstName} ${secondName}`);
}

var context = {
    sayHello() {
        return 'Hello';
    }
}

const firstName = 'Alex';
const secondName = 'Perry';

sayHello.call(context, firstName, secondName); //Hello Alex Perry

- same as invoking a function as you would do normally, however the difference is that you also get to specify the functions context

apply

function sayHello(firstName, secondName) {
    console.log(`${this.sayHello()} ${firstName} ${secondName}`);
}

var context = {
    sayHello() {
        return 'Hello';
    }
}

const firstName = 'Alex';
const secondName = 'Perry';

sayHello.apply(context, [firstName, secondName]); //Hello Alex Perry

- exactly the same as call apart from the fact that you pass in the functions arguments as an array and not separately.

bind

function sayHello(firstName, secondName, middleName) {
    console.log(`${this.sayHello()} ${firstName} ${middleName} ${secondName}`);
}

var context = {
    sayHello() {
        return 'Hello';
    }
}

const firstName = 'Alex';
const secondName = 'Perry';
const middleName = 'James';

const boundFunc = sayHello.bind(context, firstName, secondName);

boundFunc(middleName); //Hello Alex James Perry
  • The bind method enables you to pass arguments to a function without invoking it.
  • Instead, it returns a new function with the arguments bound preceding any further arguments.

JS Module Pattern

  1. Maintainability - lessen the dependencies on parts of the codebase. Updating a single module is much easier when the module is decoupled from other pieces of code.
  2. Namespacing - it’s common to have “namespace pollution”, where completely unrelated code shares global variables.
  3. Reusability - a module that we can reuse over and over again
  4. Readability - Easy to understand

Module example

var s,
NewsWidget = {

  settings: {
    numArticles: 5,
    articleList: $("#article-list"),
    moreButton: $("#more-button")
  },

  init: function() {
    s = this.settings;
    this.bindUIActions();
  },

  bindUIActions: function() {
    s.moreButton.on("click", function() {
      NewsWidget.getMoreArticles(s.numArticles);
    });
  },

  getMoreArticles: function(numToGet) {
    // $.ajax or something
    // using numToGet as param
  }

};

Module example...

/** file contents of assets/global.js */


//= require common/library.js

//= require module/news-widget.js
//= require module/some-other-widget.js

(function() {

  NewsWidget.init();

  SomeOtherModule.init();

})();

References

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

  • https://alexperry.io/personal/2016/04/03/How-to-use-apply-bind-and-call.html

  • https://css-tricks.com/how-do-you-structure-javascript-the-module-pattern-edition/

Better Javascript

By Datt Dongare

Better Javascript

Write javascript better way. Understand the functions and advanced javascript. Javascript modular pattern.

  • 757