JS functions

by Kirill Tofan

Lecture plan

  • Scope
  • Functions
  • Live coding (if we have enough time)

THANKS!

Scope

Scope

  • Global (in browser - window)

  • Local(function or block)

Hoisting

// 1) unexisted Variable
console.log(unexistedVariable); // ReferenceError: unexistentVariable is not defined

// 2) Hoisting
console.log(hoistedVariable); // undefined
var hoistedVariable = 'hello';
console.log(hoistedVariable); // 'hello'

// 3) Temporary Dead Zone
console.log(TDZVariable); // ReferenceError: Cannot access 'TDZVariable' before initialization
const TDZVariable = 'hello';
console.log(TDZVariable); // 'hello'

Closure

Each function creates a closure!

yes, always

yes, I'm sure)

function closureCreator(closedVariable) {
  const localClosedVar = a + 1;
  
  return function () {
    console.log(a, b, c, closedVariable, localClosedVar);
  }
}

var a = 1;
var newFunc = closureCreator(10);
a = 100;
var b = 2;
newFunc(); // 100 2 undefined 10 2
var c = 3;

Creating a 'private' variables with help of closures

function closureCreator(initialValue) {
  const privateCounter = initialValue;

  return function() {
    return privateCounter
  }
}

const getValue = closureCreator(5);
console.log(getValue()); // 5
console.log(privateCounter); // ReferenceError: privateCounter is not defined

Is it really Const?

const numbers = [1, 2, 3, 4];

numbers[1] = 'new value';
const number = 1;

number = 5 // TypeError: Assignment to constant variable.
const numbers = [1, 2, 3, 4];

numbers.pop();
console.log(numbers);

Functions

Function types

Function expression

Function declaration

IIFE(Immediately Invoked Function Expression)

Arrow funcitons

function test() {
    // function's code
}
const test = function () {
    // function's code
}
(function () {
    // function's code
})();
const test = () => {
    // function's code
};

What does the compiler sees

greeting(); // Hello, undefined

function greeting() {
  console.log(`Hello, ${name}`);
}
var name = 'Petia';
var name;
function greeting() {
  console.log(`Hello, ${name}`);
}

greeting(); // Hello,  undefined
name = 'Petia';

Function's return value

function sum(a, b, c) {
  const sum = a + b + c;
}

sum(1, 2, 3) // returns undefined

sum.length  // 3
function sum(a, b, c) {
  const sum = a + b + c;
	
  return sum;
}

sum(1, 2, 3) // returns 6

Note:

  • Constructor function (with new)

Passing by value  vs

by reference

function incrementValue(param) {
  param = param + 1;
  console.log('2', param);
}

var number

console.log('1', number);
incrementValue(number) // 3
console.log('3', number);
function incrementReference(param) {
  param.value = param.value + 1;
  console.log('2', param);
}

var obj = { value: 2 };

console.log('1', obj);
incrementReference(obj) // { value: 3 }
console.log('3', obj);

Arguments

function test(a) {
  console.log(a, arguments);
}

test(); // undefined
test(1); // 1
function test(a = 0) {
  console.log(a, arguments);
}

test(); // 0;
test(1); // 1;
function test(a = 0) {
  let args = Array.from(arguments);
//   let args = [].slice.call(arguments);
  // args.map(arg => arg + 100);

  console.log(a, args);
}

test(1, 2, 3); // 1, [1, 2, 3]
function test(a = 0, ...restArgs) {
  console.log(a, restArgs);
}

test(1, 2, 3); // 1, [2, 3]

Context

this

Function

vs

Method

Function - "Free"

function test() {
  // function body
}

test();

Method - Belongs to object

const person = {
  firstName: 'Peter',
  getName: function() {
      // function body
  },
};

person.getName();

this

const person = {
  firstName: 'Peter',
  getName: function() {
      console.log('Person name - ' + this.firstName);
  },
};

person.getName() // Peter;

const getNewName = person.getName;
getNewName(); // undefinde

Rewrite the execution context

  • call

  • apply

bind

Call function with provided context

Creates a new function, which is 'bound' on provided context

Function as a constructor

function personConstructor(name) {
  this.firstName = name;
  this.getName = function() {
    console.log('Person name - ' + this.firstName);
  }
}

const person = new personConstructor('Peter'); // returns { firstName 'Peter', getName: f()}

Arrow functions

const sum = (a, b) => a + b;

const sum = (a, b) => {
  return a + b;
}
  • no own this
  • no arguments (but you can use spread)
  • cannot be used as a  constructor

A bit of functional programming

Pure functions

function pureSum (a, b) {
  	const sum = a + b;
	console.log(sum);

	return sum;
}

pureSum(1, 2) // 3
pureSum(1, 2) // 3
pureSum(1, 2) // 3
const sum = 1;

function pureSum (b) {
  	sum += b;
	console.log(sum);

	return sum;
}

pureSum(2) // 3
pureSum(2) // 5
pureSum(2) // 7

Not Pure

Pure

First class Functions

All functions in JS is First-class functions

Functions in JS can be:

  • stored in a variable, object, or array
  • passed to a function as an argument
  • returned from a function

Callbacks

function logger(data) {
  console.log(data);
}

function sum(a, b, callback) {
	const sum = a + b;

	callback(sum);
}

sum(1, 2, logger);

Bind polyfill

  • Remember the context
  • remember the arguments
  • Returns the new function

Currying

// const add = x => y => x + y;

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

const increment = add(1);
const addTen = add(10);

increment(2); // 3
addTen(2); // 12

Try to write own curry() function

Composition

const increment = x => x + 1;
const decrement = x => x - 1;
const addTen = x => x + 10;
const square = x => x * x;
const half = x => x / 2;


const result = half(decrement(addTen(increment(square(10)))));
// result = 55  // ((10 ^ 2) + 1 + 10 - 1) / 2
const result = compose(
  half,
  decrement,
  addTen,
  increment,
  square
)(10);

Thanks!

Telegram: @KVtofan

JS Functions and Scope

By kirill_tofan

JS Functions and Scope

  • 388