arozwalak
7/13/2015 - 2:18 PM

Javascript: Functions

Javascript: Functions

// named function expression
var add = function add(a, b) {
  return a + b;
};

// function expression, a.k.a. anonymous function
var add = function (a, b) {
  return a + b;
};

The name property is useful when using debuggers, such as Firebug, or when calling the same function recursively from itself; otherwise you can just skip it.

// function declaration
function foo() {
  // function body goes here
}

Declarations Versus Expressions: Names and Hoisting

// this is a function expression,
// pased as an argument to the function `callMe`
callMe(function () {
  // I am an unnamed function expresssion
  // also known as an anonymous function
});

// this is a named function expression
callMe(function me() {
  // I am a named function expression
  // and my name is "me"
});

// another function expression
var myObject = {
  say: function () {
    // I am a function expression
  }
};

Function declarations

// global scope
function foo() {}

function local() {
  // local scope
  function bar() {}
  return bar;
}

Function's name Property

function foo() {} // declaration
var bar = function () {}; // expression
var baz = function baz() {}; // named expression

foo.name; // "foo"
bar.name; // "" or undefined in IE
baz.name; // "baz"

Callback Pattern

function writeCode(callback) {
  // do something
  callback();
  // ...
}

function introduceBugs() {
  // ... make bugs
}

writeCode(intrduceBugs);

Example 1

var findNodes = function (callback) {
  var i = 100000,
      nodes = [],
      found;
  
  // check if callback is callable {
  if (typeof callback !== "function") {
    callback = false;
  }
  
  while (i) {
    i -= 1;
    
    // complex logic here...
    
    // now callback:
    if (callback) {
      callback(found);
    }
    
    nodes.push(found);
  }
  
  return nodes;
};

// a callback function
var hide = function (node) {
  node.style.display = "none";
};

// find the nodes and hide them as you go
findNodes(hide);

// passing an anonymous callback
findNodes(function (node) {
  node.style.display = "block";
};

Example 2

var myapp = {};
myapp.color = "green";
myapp.paint = function (node) {
  node.style.color = this.color;
};

var findNodes = function (callback, callback_obj) {
  // ...
  if (typeof callback === "function") {
    callback.call(callback_obj, found);
  }
  // ...
};

findNodes(myapp.paint, myapp);
findNodes("paint", myapp);

var findNodes = function (callback, callback_obj) {
  if (typeof callback === "string") {
    callback = callback_obj[callback];
  }
  
  if (typeof callback === "function") {
    callback.call(callback_obj, found);
  }
};

Asynchronous Event Listener

document.addEventListener("click", console.log, false);

Returning Functions

var setup = function () {
  var count = O; // not accessible from outside
  return function () {
    return (count += 1);
    
// usage
var next = setup();
next(); // returns 1
next(); // returns 2
next(); // returns 3

Self-Defining Functions

var scareMe = function () {
  alert("Boo!");
  
  scareMe = function () {
    alert("Double boo!");
  };
};

// using the self-defining function
scareMe(); // Boo!
scareMe(); // Double boo!

Immediate Functions

(function () {
  alert('watch out');
}());

Returned Values from Immediate Functions

var result = (function () {
  return 2 + 2;
}());

// or just

var result = function () {
  return 2 + 2;
}();
var getResult = (function () {
  var res = 2 + 2;
  return function () {
    return res;
  };
}());
var o = {
  message: (function () {
    var who = "me",
        what = "call";
    return what + " " + who;
  }()),
  getMsg: function () {
    return this.message;
  }
};

// usage
o.getMsg(); // "call me"
o.message;  // "call me"

Immediate Object Initialization

({
  // here you can define settings values
  // a.k.a. configuration constants
  maxwidth: 600,
  maxheight: 400,
  
  // you can also define utility methods
  gimmeMax: function () {
    return this.maxwidth + "x" + this.maxheight;
  },
  
  // initialize
  init: function () {
    console.log(this.gimmeMax());
    // more init task...
  }
}).init();
// this works same
({...}).init();
({...}.init());

Init-time branching

// the interface
var utils = {
  addListener: null,
  removeListener: null
};

// the implementation
if (typeof window.addEventListener === 'function') {
  utils.addListener = function (el, type, fn) {
    el.addEventListener(type, fn, false);
  };
  utils.removeListener = function (el, type, fn) {
    el.removeEventListener(type, fn, false);
  };
} else if (typeof document.attachEvent === 'function') { // IE
  utils.addListener = function (el, type, fn) {
    el.attachEvent('on' + type, fn);
  };
  utils.removeListener = function (el, type, fn) {
    el.detachEvent('on' + type, fn);
  };
} else { // older browsers
  utils.addListener = function (el, type, fn) {
    el['on' + type] = fn;
  };
  utils.removeListener = function (el, type, fn) {
    el['on' + type] = fn;
  };
}