Functions

Function as normal function

function add(a, b) {
    return a + b;
}

Function as method


var Rectangle = {
    x: 2,
    y: 4,
    perimeter : function() {
        return (this.x+this.y)*2;
    }
}

Rectangle.perimeter(); // 12
            

Function as constructor

function Rectangle(x, y) {
    this.x = x;
    this.y = y;
}

var rect = new Rectangle(1, 2);
function declaration

VS

function expression

Function declaration

function functionName([parameters]){
    //functionBody
};

add(2, 4); // works

function add(x, y) {
    return x + y;
}

Function declaration

alert(x); // prints function body

var x = 10;
alert(x); // 10

x = 20;
function x() {};
alert(x); // 20

Anonymous function expression

variableName = function([parameters]){
    //functionBody
};

add; //undefined
add(2, 4); // this raises a TypeError

var add = function(x, y) {
   return x + y;
}

Named function expression

variableName = function functionName([parameters]){
    //functionBody
};


var foo = function bar() {
    bar(); // works
}

bar(); // ReferenceError
             

New function

variableName = new Function( 
    /*
        parameters 
    */, 
    functionBody
);

var add = new Function(“x”, “y”, “return x + y”);

Strategy of passing arguments to function

Primitive types are manipulated by value.

Object types are manipulated by sharing.


function func(obj){
    obj.prop1 = 5;
    obj = {};
}

var data = {};

func(data);
console.log(data); // {prop1: 5}
                

First-class functions

A first-class function is one that may participate as a normal data, i.e. be created literally at runtime, be passed as an argument, or be returned as a value from another function.

Function as data

function square(x) { return x * x; }

var pointerToSquare = square;
Assert(pointerToSquare(3) == 9);

var newArray = ["a", "b", "c", pointerToSquare];
Assert(newArray[3](4) == 16);

var obj = { "square": square };
Assert(obj.square(5) == 25);

Static members

function MyMath() {
    //math here...
}

MyMath.Pi = 3.14;


function getNewId() {
    if (!getNewId.lastId) getNewId.lastId = 0;
    return ++getNewId.lastId;
}

return statement

return expression;




return; // return undefined

If there is no expression, then the return value is undefined.
Except for constructors, whose default return value is this.

Function arguments

  1. If a function is called with too many arguments, the extra arguments are ignored.

  2. If a function is called with too few arguments, the missing values will be undefined.
Optional arguments and argument types
function NodeText(/*domNode|String*/ node, /*String?*/ text) {

    if (typeof node == “string”){
        node = document.getElementById(node);
        if (!node) return;
    }
    
    if(text != null) {
        node.innerHTML = text;
    } else {
        return node.innerHTML ;
    }
}

Options objects

var printEmployeeInformation = function (info) {
    var firstName = info.firstName || "";
    var lastName = info.lastName || "";
    var position = info.position || "";
    var office = info.office || "K1";
    var phone = info.phone || "911";
    var internalPhone = info.internalPhone || "";
    var manager = info.manager || "";
    ///…
}

var info = { firstName: “Bruce", lastName: "Wayne", internalPhone: “111" };
info.office = "K1/5";
printEmployeeInformation(info);
info.office = "K1";
printEmployeeInformation(info);

Pseudo parameters

  • arguments
  • this

The "arguments" object

arguments contains the following properties:

  • callee – reference to the current function
  • length – quantity of real passed arguments
  • properties-indexes – parameters from the invocation

It is an array-like object.

foo(10, 20);

function foo(x, y, z) {
    // quantity of defined function arguments (x, y, z)
    alert(foo.length); // 3
    
    // quantity of really passed arguments (only x, y)
    alert(arguments.length); // 2
    
    // reference of a function to itself
    alert(arguments.callee === foo);
    
    // parameters sharing
    alert(x === arguments[0]); // true
    alert(x); // 10
    
    alert(arguments[2]); // undefined
}

The "arguments" object

function sum() {
    var n = arguments.length;
    var total = 0;

    for (var i = 0; i < n; i++) {
        total += arguments[i];
    }

    return total;
}
var ten = sum(1, 2, 3, 4);

This

determined on runtime and immutable

This

function Car(model, color) {
    this.model = model;
    this.color = color;
    this.changeGear = function (value) {
         this.currentGear = value;
         //....
    }
}

This in the global context

var x = 20;

console.log(x == window.x);
console.log(this.x == x);
console.log(this.x == window.x);

This in the function context


function foo() {
    console.log(this.bar);
}

var x = { bar: 1 };
var y = { bar: 2 };

x.foo = foo;
y.foo = foo;

x.foo(); // 1
y.foo(); // 2

var bar = 3;
foo(); //3

new foo(); // undefined

Value of this in function is determined by the form on invocation but not context of definition.

Function form

foo();

function foo(){
    this === window; // Fixed in ES5/Strict
}

Method form


var test = {
    “name”: “Max”,
    “foo”: function(){
        alert(this.name);
    }
};

test.foo(); //this === test
test[“foo”](); // this === test

var foo = test.foo;
foo(); // this === window
             

Constructor form

function Car(model, color) {
    this.model = model;
    this.color = color;
    this.changeGear = function () {
        //…
    }
}

var bmw1 = new Car(“z1", “black")
bmw1.changeGear();

Constructor form

function Car(model, color) {
    this.model = model; // this === window
    this.color = color;
    this.changeGear = function () {
        //…
    }
}

var bmw1 = Car(“z1", “black"); // without new
bmw1.changeGear();

Constructor form

function Car(model, color) {
   var that = {};
   that.model = model;
   that.color = color;
   that.changeGear = function () {
       //…
   }
   return that;
}

var bmw1 = Car(“z1", “black"); // without new
bmw1.changeGear();

Inner form

function Car(model, color) {
    this.model = model;
    this.color = color;
    this.changeGear = function () {
        var that = this;
        var inner = function() {
            //this === window
            // Use that instead of this here
        }

        inner();
    }
}

Explicit setting of this

foo.apply(thisObject,[arguments])
foo.call(thisObject, / *arguments */);

A function’s apply or call method allows for calling the function, explicitly specifying this.

Arguments / apply

var array = [1,2,368,10,45];

Math.max.apply(Math,array); //368

Borrowing methods

notmyobj.doStuff.call(myobj, param1, p2, p3);
notmyobj.doStuff.apply(myobj, [param1, p2, p3]);

function f() {
    var args = [].slice.call(arguments, 1, 3);
    
    return args;
}

f(1,2,3,4,5,6); // [2, 3]
             

Bind


var x = 9; // global variable

var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX(); // 9, because in this case, "this" refers to the global object

// Create a new function with 'this' bound to module
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
             

Lexical (or Static) Scope

function f() {
    var x = 2;
    function g() {
        alert(x);
    }
}

Static structure of a program determines the scope of a variable.

Lexical (or Static) Scope

var z = 10;
function foo() {
    alert(z);
}

foo();

(function () {
    var z = 20;
    foo();
})();

Closures

var inner;
function outer(){
    var local = 1;
    
    inner = function(){
        return local;
    };
}

inner();
outer();
inner();

Closures

function doNTimes(n, action) {
    function doNTimesRec(x) {
        if (x >= 1) {
            action();  // (1)
            doNTimesRec(x-1);
        }
    }
    doNTimesRec(n);
}

Functions Stay Connected to Their Birth Scopes

function createInc(startValue) {
    return function (step) {
        startValue += step;
        return startValue;
    };
}

var inc = createInc(5);
inc(1); // 6
inc(2); // 8

Closures

function sayHello() {
    var text = "Hello #1";
    var sayAlert = function() { alert(text); }
    
    text = "Hello #2";
    sayAlert();
}

Private Members

var obj = new function () {
    var privateVariable;
    function privateFunction(x) {
        // privateVariable
    }
    return {
        firstMethod: function (a, b) {
            // access to privateVariable
        },
        secondMethod: function (c) {
            // access to privateVariable
            // access to privateFunction()
        } 
    };
};

Immediately-Invoked Function Expression

(function () { // open IIFE
    // inside IIFE
}()); // close IIFE


(function (x, y) {
    console.log(x + y);
}(2,4));

why IIFE ?

Avoiding global variable or hiding variables from global scope.

(function () {
    var x = 2;
    var y = 4;
}());

typeof window.x === “undefined”;
typeof window.y === “undefined”;

Avoiding variable sharing.


function f() {
    var result = [];

    for (var i=0; i<3; i++) {
        var func = function () { return i; };
        result.push(func);
    }

    return result;
}
console.log(f()[0]()); // 3
console.log(f()[1]()); // 3
console.log(f()[2]()); // 3

Avoiding variable sharing.

function f() {
    var result = [];
    for (var i=0; i<3; i++) {
        (function () { // step 1: IIFE
            var pos = i; // step 2: copy
            var func = function () { return pos; };
            result.push(func);
        }());
    }

    return result;
}
console.log(f()[0]()); // 0
console.log(f()[1]()); // 1
console.log(f()[2]()); // 2

Functions

By andrei_bibik

Functions

  • 478