Scope, Functions, Callbacks

Tonight's Topics

  1. Terminology Review
  2. Scope
  3. First Class & Higher Order Functions
  4. Callbacks

Key Terms

  1. Variable declaration
  2. Variable assignment
  3. Function Declaration
  4. Function Expression
  5. Anonymous Function
  6. Function Call / Invocation
  7. Parameters
  8. Arguments
  9. Return Values
  10. Methods

1. Variable Declaration

2. Variable Assignment

var name;
var age;
var favoriteColor;
name = "Elie";
age = 74;
favoriteColor = "purple";
var name = "Whiskey";
var age = 4;
var favoriteColor = null;

Using a keyword (e.g. "var") to set aside space for some data.

Using an assignment operator (e.g. "=") to set a value

Variable declaration with assignment

Just remember that declaration always happens first!

3. Function Declaration

4. Function Expression

function addTwo(x, y) {
  return x + y;
}
var addTwoFunc = function addTwo(x, y) {
  return x + y;
}
var subtractTwo = function(x, y) {
  return x - y;
}

Using the function keyword lets you declare a function.

Assign a function to a variable in-line

5. Anonymous Function

Outside of a function declaration, functions do not need names

6. Function Call / Invocation

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

addTwo(99, 1); // 100

Run the code in the function body with its name followed by parentheses ()

7. Parameters

variables declared when defining a function

8. Arguments

Values you assign ("pass") to parameters.

Every function has a built-in arguments array of values.

9. Return Value

The value resolved by the return statement inside the function. The default is undefined.

10. Methods

In JavaScript, we call generally call functions "methods" when they live on data types.

var myArr = [];

myArr.push(5); // push is a method


function printList(arr) {
  for (let i of arr) {
    console.log(arr);
  }
}

printList(myArr); // printList is a regular old function

If you called anything.something(), then .something() would be referred to as a method.

Lexical Scope

Like most programming languages, JavaScript uses lexical scoping, which means variables are by default attached to the scope where they are originally declared in the code.

Note: JavaScript also utilizes dynamic scope using the "this" keyword, but that is an advanced topic for another time.

var name = 'Michael';  // global scope by default

// ... 10 thousand lines later ...

console.log(name);  // Michael (assuming it hasn't been reassigned)

Functions Create New Scopes

In JavaScript, most often we will use functions to create new layers of scope.

var scopey = 'I was declared in the global scope.';

function newScope() {
  var scopey = 'I was declared in the inner scope';
  console.log(scopey);
}

console.log(scopey);
// I was declared on the global scope

newScope(); 
// I was declared in the inner scope

Shadowing

Scoping Rules

  • Children have access to items in their parents' scopes.
  • Parents do not have access to items in their children's scopes.
var rithm = 'rithm'; // global scope
        
            parentFunction(myArg) {
 console.log(rithm);





}
        
childFunction(){
  console.log(myArg, rithm);

}

Scopes can be nested within each other predictably:

parentFunction('Algo'); // Algorithm        
childFunction();

var globalScope = 'I am in the global scope.';

function outer() {

  console.log(globalScope);
  var outerScope = "I am in the outer function's scope";

  inner();  // note this function is "hoisted"
  
  function inner() {
     console.log(outerScope);
     console.log("I am in the inner function's scope");
  }

}

console.log(globalScope); 
// I am in the global scope.

console.log(outerScope); 
// undefined

outer();
// I am in the global scope.
// I am in the outer function's scope.
// I am in the inner function's scope.

inner(); // ReferenceError: inner is not defined

Scope Takeaways

1. In JavaScript, the default scope is lexical, meaning variables live in the scope where they were physically declared in the code

2. Use functions to create different scopes. Function parameters are scoped inside the function the same as if they said "var x" at the top of the function body.

3. Scopes can be nested. A child scope can access variables in parent scopes. A parent scope cannot access variables in its children's scopes.

JavaScript has first class functions, meaning that functions can be treated just like other data types

First Class Functions

We've seen this before with function expressions:

var favorite = function(thing, value) {
  return `My favorite ${thing} is ${value}.`;
}

console.log(favorite('food', 'pizza'));
// My favorite food is pizza.

In the above example, when the variable favorite gets assigned to a function, we can invoke it like one!

Functions as Parameters and Arguments

function first(anotherFunc) {
  // SPOILER ALERT! I AM A HOF!
  return anotherFunc();
}

function second() {
  console.log('hello Whiskey');
}

first(second); // hello Whiskey

Function parameters can be designed to expect functions as arguments.

Here is a function that receives a function as an argument and then invokes its argument in its function body:

Higher Order Functions

Math Nerd Alert!

Higher Order Functions are more of a mathematical concept rather than a feature specific to programming languages.

A Higher Order Function (often abbreviated HOF) is a function that does at least one of the following (or both):

  • Accepts a function as a parameter
  • Returns a function as a result

HOF Example


function myHOF(myFunc, myArg) {
  return myFunc(myArg);
}


myHOF(console.log, 'hello from the HOF');
// hello from the HOF

Here's a HOF that takes a function with an argument, and calls it.

First Class and HOF Takeaways

  1. First Class Functions programmatically behave like other types
  2. Higher Order Functions take a function, return a function, or both

Callback Pattern

Lots of built-in functions in JavaScript are Higher Order Functions (HOFs) that are designed to accept callbacks.

The callback pattern usually looks like this:

function greeting(name) {
  alert('Hello ' + name);
}

function processUserInput(callback) {
  var name = prompt('Please enter your name.');
  callback(name);
}

processUserInput(greeting);

Callbacks In-Line

Usually callbacks are defined in-line with anonymous functions.

function eachItem(obj, cb) {
  for (let key in obj) {
    cb(key, obj[key]);
  }
}

let obj = { name: 'Whiskey', otherName: 'Hazel' };
eachItem(obj, function(key, val) {
  console.log('The key is ' + key + '. the value is ' + val + '.');
});

// The key is name. The value is Whiskey.
// The key is otherName. The value is Hazel.

Must-Know Functions that Take Callbacks

We'll discuss the following functions that all take callbacks:

1. setTimeOut

2. Array forEach

3. Array map

4. Array filter

5. Array reduce

6. Array sort

1. setTimeOut

setTimeout(function() {
  alert('yoooo');
}, 1000);
  • The first argument is a callback function
  • The second argument is the number of milliseconds to wait before executing the callback

2. Array forEach

[1,2,3].forEach(function(element, index) {
  console.log(element, index);
});

/*
    1 0
    2 1
    3 2
 */
  • There is a new callback function for every array element.
  • The functions take two arguments, the current array element and the current index.
  • The functions return undefined

3. Array map

var oldArr = [1,2,3];
var newArr = oldArr.map(function(element, index) {
  return element * index;
});

console.log(newArr);

/*
    [0, 2, 6]
*/
  • The map method returns an entirely new array
  • There is a new callback function for every array element.
  • The functions take two arguments: the current array element and the current index.
  • The return value of each callback is the new element value in the new array.

4. Array filter

var oldArr = [1,2,3,4,5,6,7,8,9,10]
var newArr = oldArr.filter(function(element, index) {
  return element % 2 === 0;
});

console.log(newArr);

/*
    [2, 4, 6, 8, 10]
*/
  • There is a new callback function for every array element.
  • The callbacks take two arguments: the current array element and the current index.
  • The filter method returns an entirely new array
  • The return value of each callback is true / false whether the element should be included in the new array

5. Array reduce

var oldArr = [3, 2, 1]
var countDown = oldArr.reduce(function(previous, current, index) {
  return previous + ' ' + current;
}, "ready");

console.log(countDown);

/*
    ready 3 2 1;
*/
  • There is a new callback function for every array element.
  • The callbacks take three arguments: the previous callback's return value, the current element, and the current index.
  • The reduce method can transform an array into any other type
  • The second argument is the optional initial value

6. Array sort

var myArr = [10, 3, 2, 7, 9, 11, 1];
myArr.sort(function(a, b) {
  return a - b;
})

console.log(myArr);
/*
    1, 2, 3, 7, 9, 10, 11
*/
  • Array sort modifies the current array in-place
  • The callback is a comparator function that gets passed to the underlying sorting algorithm
  • For any two numbers a and b, return 0, 1, or -1.
    • 0 means they are equal
    • greater than 0 means a is greater than b
    • less than 0 means b is greater than a

Scope, Functions, and Callbacks

By Michael Hueter

Scope, Functions, and Callbacks

An overview of functions, looking at scope and callbacks. For advanced beginners.

  • 764