JS Functions

Function

Is a block of code designed to perform a particular task

Is executed when "something" invokes it (calls it).

function killSomeone() {
  alert( 'Drakaris' );
}

killSomeone();
function showMessage(message) {
  message = message + '!';
  alert( message ); // Hello world!
}

showMessage('Hello World');
function showMessage(from, message) {
  from = from + ': ';
  alert( message );
}

showMessage('Elon Musk', 'Hello Mars' ); // Elon Musk: Hello Mars
showMessage('Elon Musk'); // Elon Musk: undefined
function showMessage(from, message) {
  from = from + ': ';
  message = message || 'Bye Earth'
  alert( message );
}

showMessage('Elon Musk', 'Hello Mars' ); // Elon Musk: Hello Mars
showMessage('Elon Musk'); // Elon Musk: Bye Earth
function calcD(a, b, c) {
   return b*b - 4*a*c;
}

var test = calcD(-4, 2, 1);
alert(test); // 20
function checkAge(age) {
  if (age > 18) {
    return true;
  } else {
    return confirm('DO you have a permission?');
  }
}

var age = prompt('Your age?');

if (checkAge(age)) {
  alert( 'Approved' );
} else {
  alert( 'Declined' );
}
function showMovie(age) {
  if (!checkAge(age)) {
    return;
  }

  alert( "Movie is not for all" );
  // ...
}

Function as a data

function sayHi() {
  alert( "Valar Morghulis" );
}

alert( sayHi );
function sayHi() {   // (1)
  alert( "Valar Morghulis" );
}

var func = sayHi;    // (2)
func(); // Valar Morghulis // (3)

sayHi = null;
sayHi();             // error (4)

Function declaration

vs

Function expression

// Function Declaration
function sum(a, b) {
  return a + b;
}

// Function Expression
var sum = function(a, b) {
  return a + b;
}
sayHi("Sansa"); // Hi, Sansa

function sayHi(name) {
  alert( "Hi, " + name );
}
sayHi("Sansa"); // error

var sayHi = function(name) {
  alert( "Hi, " + name );
}
var sum = new Function('a,b', ' return a+b; ');

var result = sum(1, 2);
alert( result ); // 3
var a = "NOT in the castle";

function whereIsArya() {
  var a = "in the castle";

  var func = new Function('', 'alert(a)');

  return func;
}

whereIsArya()(); // NOT in the castle

Strategy of passing arguments to function

Primitive types are manipulated by value.

Object types are manipulated by sharing.

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

var data = {};

func(data);
console.log(data); // {prop: 5}
function func(obj){
    obj.push(5);
    obj.push(6);
    obj = [];
}

var data = [];

func(data);
console.log(data); // [5, 6]

Static members

function getThirdEye() {
    if (!getThirdEye.eyesCount)
        getThirdEye.eyesCount= 0;
    return ++getThirdEye.eyesCount;
}

Function.arguments

function sayHi() {
  for (var i = 0; i < arguments.length; i++) {
    alert( "Valar " + arguments[i] );
  }
}

sayHi("morghulis", "dohaeris"); // 'Valar morghulis', 'Valar dohaeris'

Array

function showWarning(options) {
  var width = options.width || 200; // по умолчанию
  var height = options.height || 100;

  var contents = options.contents || "Alert";

  // ...
}

var opts = {
  width: 400,
  height: 200,
  contents: "Text"
};

showWarning(opts);

opts.contents = "New text";

showWarning(opts);

Duck Typing

If it looks like a duck, swims like a duck and quacks like a duck, then it probably is a duck (who cares what it really is)

var something = [1, 2, 3];

if (something.splice) {
  alert( 'Это утка! То есть, массив!' );
}

LexicalEnvironment

&

[[Scope]]

function sayHi(name) {
  /* LexicalEnvironment = { 
        name: 'Snow',
        phrase: undefined
    } */
  var phrase = "Hi, " + name;

  /* LexicalEnvironment = {
        name: 'Snow',
        phrase: 'Hi, Snow'
    }*/
  alert( phrase );
}

sayHi('Snow');
function sayHi(name) {

  var phrase = "Hi, " + name;


  alert( phrase );
}

sayHi('Snow');

LexicalEnvironment

var userName = "Night King";

function sayHi() {
  alert( userName ); // "Night King"
}

[[Scope]]

var secondPart = 'morghulis';

function sayHi(phrase) {
  alert(phrase + ', ' + secondPart);
}

sayHi('Valar');  // Valar morghulis (*)

secondPart = 'dohaeris';

sayHi('Valar'); // Valar dohaeris (**)

Always current value

[[Scope]] = {
    secondPart = 'morghulis';
}
[[Scope]] = {
    secondPart = 'dohaeris';
}
function sayHiBye(firstName, lastName) {

  alert( "Hi, " + getFullName() );
  alert( "Bye, " + getFullName() );

  function getFullName() {
    return firstName + " " + lastName;
  }

}

sayHiBye("Daenerys", "Targaryen");
// Hi, Daenerys Targaryen; Bye, Daenerys Targaryen

Nested functions

Closures

function makeCounter() {
// LexicalEnvironment = { currentCount: undefined }
  var currentCount = 1;
// LexicalEnvironment = { currentCount: 1 }

  return function() { // [[Scope]] -> LexicalEnvironment (**)
    return currentCount++;
  };
}


var counter = makeCounter(); // (*)

alert( counter() ); // 1, [[Scope]] -> {currentCount: 1}
alert( counter() ); // 2, [[Scope]] -> {currentCount: 2}
alert( counter() ); // 3, [[Scope]] -> {currentCount: 3}

var counter2 = makeCounter();
alert( counter2() ); // 1
function() { // [[Scope]] -> {currentCount: 1}
  return currentCount++;
};
function makeCounter() {
  var currentCount = 1;

  return function() {
    return currentCount++;
  };
}


var counter = makeCounter();

alert( counter() );
alert( counter() );
alert( counter() );

var counter2 = makeCounter();
alert( counter2() );

THIS

В МОМЕНТ ВЫЗОВА

function func() {
  alert( this ); // [object Window]
}

func()

1

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

3

var o = {
  prop: 37,
  f: function() { return this.prop; }
};
console.log(o.f()); // 37

2

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42
var globalObject = this;
var foo = (() => this);

var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

console.log(foo.call(obj) === globalObject); // true

foo = foo.bind(obj);
console.log(foo() === globalObject); // true
var obj = { bar : function() {
                    var that = this;
                    var x = (() => that);
                    return x;
                  }
          };

var fn = obj.bar();
console.log(fn() === obj); // true
var user = {
  name: "Arya",
  hi: function() { alert(this.name); },
  bye: function() { alert("Bye"); }
};

user.hi();
(user.name == "Arya" ? user.hi : user.bye)(); // undefined

4

5

function C(){
  this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
function C2(){
  this.a = 37;
  return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
elements[i].addEventListener('click', func, false);

function bluify(e){
  console.log(this === e.currentTarget); //true
}
<button onclick="alert(this.tagName.toLowerCase());">
  Показать this
</button>

<button onclick="alert((function(){return this}()));">
  Показать вложенный this
</button>

6

Call

func.call(context, arg1, arg2, ...);
function showFullName() {
  alert( this.firstName + " " + this.lastName );
}

var user = {
  firstName: "Jon",
  lastName: "Snow"
};

showFullName.call(user) // "Jon Snow"
function printArgs() {
  var argStr = Array.prototype.join.call(arguments, ':');
  alert( argStr );
}

printArgs(1, 2, 3);

Method borrowing

Apply

func.apply(context, [arg1, arg2]);
var arr = [];
arr.push(1);
arr.push(5);
arr.push(2);

alert( Math.max.apply(null, arr) ); // 5

Bind

var user = {
  firstName: "Jon Snow",
  sayHi: function() {
    alert( this.firstName );
  }
};

setTimeout(user.sayHi, 1000); // undefined (not Jon Snow!)
var user = {
  firstName: "Jon Snow",
  sayHi: function() {
    alert( this.firstName );
  }
};
var f = user.sayHi;
setTimeout(f, 1000); // context of user is lost
var user = {
  firstName: "Jon Snow",
  sayHi: function() {
    alert( this.firstName );
  }
};

setTimeout(function() {
  user.sayHi(); // Jon Snow
}, 1000);

1

var user = {
  firstName: "Jon Snow",
  sayHi: function() {
    alert( this.firstName );
  }
};

setTimeout(user.sayHi.bind(user), 1000);

2

function bind(func, context) {
  return function() { // (*)
    return func.apply(context, arguments);
  };
}
var user = {
  firstName: "Jon Snow",
  sayHi: function() {
    alert( this.firstName );
  }
};
const f = user.sayHi.bind(user);
setTimeout(f, 1000);

3

Function.prototype.bind(context, arguments) {
  let that = this;
  return function() {
    return that.apply(context, arguments);
  };
}
function mul(a, b) {
  return a * b;
};

var double = mul.bind(null, 2);

alert( double(3) ); // = mul(2, 3) = 6
alert( double(4) ); // = mul(2, 4) = 8
alert( double(5) ); // = mul(2, 5) = 10

Carrying

Chaining

var o = {
    v:1,
    increment: function() {
        this.v++;
        return this;
    },
    add: function (v){
        this.v += v;
        return this;
    },
    shout: function() {
        alert(this.v);
    }
};
o.increment().add(3).shout() // 5

Immediately-Invoked Function Expression

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

why?

Private methods

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

Memoization

const add = (n) => (n + 10);
add(9);
const memoizedAdd = () => {
  let cache = {};
  return (n) => {
    if (n in cache) {
      return cache[n];
    }
    else {
      let result = n + 10;
      cache[n] = result;
      return result;
    }
  }
}

const newAdd = memoizedAdd();
console.log(newAdd(9)); // вычислено
console.log(newAdd(9)); // взято из кэша
const memoize = (fn) => {
  let cache = {};
  return (...args) => {
    let n = args[0];
    if (n in cache) {
      console.log('Fetching from cache', n);
      return cache[n];
    }
    else {
      console.log('Calculating result', n);
      let result = fn(n);
      cache[n] = result;
      return result;
    }
  }
}

const factorial = memoize(
  (x) => {
    if (x === 0) {
      return 1;
    }
    else {
      return x * factorial(x - 1);
    }
  }
);

console.log(factorial(5));
console.log(factorial(6));

JS Functions

By Victoria Budyonnaya

JS Functions

  • 369