Functions

CSCI-UA.0480-008

Back to Definitions

  • function - a named sequence of statements that performs a specific task or useful operation
  • parameter - a variable that receives an argument that is passed into a function, think of it as as the variable(s) in the function header / signature
  • call/invoke/apply - to run or execute a function
  • argument - a piece of data that is passed into a function when that function is called
  • scope - the area of the code where a name/identifier is available for access and/or use

Defining a Function

We'll take a look at 3 ways of defining functions in JavaScript

  1. function declarations
    
    function foo(arg1, arg2) {
     return arg1 + arg2; 
    } 
    
  2. function expressions
    
    const foo = function(arg1, arg2) {
     return arg1 + arg2; 
    }
    
  3. arrow functions
    
    (arg1, arg2) => { return arg1 + arg2 }    
    

Function Declarations

Function declaration syntax:


function foo(arg1, arg2) {
    return arg1 + arg2; 
} 
  1. start with the key word function (note that return type is not specified)
  2. followed by function name
  3. followed by optional comma separated parameters within parentheses (again, no types precede the arguments)
  4. and finally, the function body surrounded by curly braces (with an optional return)
    • what do you think you get back if return is omitted?undefined


We'll see later that function declarations are special in that they can used before they are declared in your code!

Function Expressions

Another way to create a function is by using a function expression (remember, functions are first-class citizens):


const doubleTheNumber = function(n) {
	return n + n;
};
console.log(doubleTheNumber(5));
  1. declare a variable
  2. set it equal to the keyword, function
  3. followed by parentheses and an optional list of parameters (separated by commas if more than one)
  4. the function body is just a block of code (surrounded by curly braces, of course! …and again with an optional return)
  5. note the semicolon at the end of the function definition (it is an assignment statement after all!)
  6. finally, the variable, doubleTheNumber, can be called/invoked because it's a function!

Function Expressions Continued

Function expressions, as the name implies, are expressions!

  1. that means that they evaluate to a value (that is… they evaluate to a function)
  2. so, you can use them anywhere values are needed… some examples:
    
    // to initialize a variable    
    const doubleTheNumber = function(n) { return n + n; };
    
    
    // as an argument
    const numbers = [1, 2, 3, 4];
    numbers.map(function(n) { return n + n; });
    
    
    // as a return value
    function f() {
     return function(n) { 
         return n + n; 
     });
    }
    

Arrow Functions

Introduced in ES6, arrow functions are a way of writing function expressions in a very concise syntax.

 (arg1, arg2) => { /* body goes here */}
  • it's a shorthand / more convenient way of writing a function expression
  • its behavior is subtly different from regular function expressions
    • it doesn't have a built in arguments object (we'll see this later)
    • its this is the value of this where it was defined (we'll talk about this later as well)

Arrow Function Syntax

There are a few ways to write arrow functions.

  • Parentheses around parameters, curly braces around body:
    
    (p1, p2, ..., pN) => { statements }
    
  • You can drop the curly braces if you have a single expression. The value of that expression will be implicitly returned if you drop curly braces:
    
    (p1, p2, ..., pN) => expression // same as { return expression; }
    
  • If there's only one parameter, you could also drop the parentheses:
    
    singleParam => { statements }
    
  • If you have no parameters, use empty parentheses:
    
    () => { statements }
    

Let's Create a Function Together

Let's create a function called myPow. It will (surprisingly) raise some number to a power:

  • two parameters: base and exponent
  • calculate the base raised to the exponent
  • return the resulting value
  • use function expression syntax to do this!

const myPow = function(base, exponent) {
	let result = 1;
	for(var i = 0; i < exponent; i++) {
		result = result * base;
	}
	return result;
};
console.log(myPow(2,0));
console.log(myPow(2,1));
console.log(myPow(2,8));

Additional Assignment Operators

That line was a bit verbose, wasn't it?


result = result * base;

We can tighten that up using another assignment operator.


var x = 3;
x *= 2;
console.log(x);

// this works with +=, -= and /= as well

Putting the FUN in Functions

Yeah, really. I said that.

This is when things start to get interesting…

Block Scope vs Function Scope

Again, scope is the area or portion of your program where a variable name or identifier is available.

  • some languages (C, Java) use blocks to create new scopes
  • ES6 does that
  • but ES5 doesn't do that (of course); instead… it only uses functions to create scope

In ES5, functions are the only constructs that can create a new scope!

(but with ES6, let and const give you block level scope!)

Scope

Variables declared at the "top level" of your program (outside of functions) and variables declared without const, let or var (in most cases) are in the global scope.

  • global variables are accessible anywhere
  • global variables are considered harmful… why?
    • because global variables are accessible everywhere, it makes things difficult to debug and fix issues as many places may read or write a value
    • when creating functions that depend on global variables, those functions will not be portable across multiple programs (as they depend on a global variable being defined)

Functions and Scope

  • parameters in a function are local to that function
  • variables declared with the keyword, var are local to the function
  • variables declared with the keywords, const or let are local to the block that they're declared in
  • variables declared without the let, const or var affect the global scope… ⊙﹏⊙
    • (actually, the nearest enclosing scope - most of the time this is global, but it could be an outer function!)
  • global variables (again) are accessible throughout your program, even from within you function's body

An Example

Based on the previous slide, what is the output of the following code?


let x = "hi!"; // hello... I'm a global variable

const f = function() {
	let x = "from f";
};

const g = function() {
	x = "from g";
};
console.log(x)
f();
console.log(x);
g();
console.log(x);

hi!
hi!
from g

Oh yeah. Always use let or const (or var) when declaring variables plz

It's Functions All the Way Down

turtles

The world is really a flat plate supported on the back of a giant tortoise;

(Let's look at nested functions)

Nested Functions

  • functions can be defined within functions
  • just create a function within another function using declarations, expressions or arrow functions
  • the variables in the outer function are available to the inner function and can be used just by using the variable name (no new declaration is needed)
  • but the variables in the inner function are local to the inner function

Without Const, Let, or Var Revisited

Variables declared without const, let, or var actually mask the variable in nearest enclosing scope (if it's not a const) (usually global, but a bit tricky for nested functions).


let x = 1;
function f() {
  let x = 2;
  function g() {
    x = 3;
    console.log(x);
  }
  g(x);
  console.log(x);
}
f();
console.log(x);


3
3
1

Nested Functions Example

What is the output of this code? What would happen if we put console.log(y) right at the end of function, outer's body?


const outer = function() {
	let x = "outside";
	let inner = function() {
		x += " modified by inside";
		let y = "inner";
	};
	console.log(x);
	inner();
	console.log(x);
};
outer();

outside
outside modified by inside
// we would get a ReferenceError if we tried to print out y from the outer function

Functions as Values

  • functions are objects… and they can exist as values, like numbers, strings, etc.
  • the names that we use for functions are just like regular variables
  • reassignment works fine!

const sayHello = function() {
	console.log("Hola!");
};

sayHello();

sayHello = function(x) {
	return x * x
};

console.log(sayHello(5));

Functions as Values Continued

You can even pass functions around, return them as values, etc.

  • describe the first function
  • what do you think the output of this code is?

const callTwice = function(f) {
	f();
	f();
};

const g = function() {
	console.log("nobody's home!");
};
callTwice(g);

nobody's home!
nobody's home!

Function Declarations Revisited

Let's take a look at function declarations again


function f(x) {
	return x;
}

Hoisting

However, functions defined in this manner, through function declarations, are hoisted to the top of the scope:

  • they're taken out of the usual flow of control
  • and brought to the top of the scope
  • even if they're defined below their first use, they'll still work…
  • (this isn't true when you create functions via assignment)

console.log(f(5));

function f(x) {
	return x;
}

Hoisting Continued

From Speaking JavaScript:

What happens when you put such a function declaration inside an if statement or a loop?

  • don’t do that
  • different JavaScript platforms in different browsers have traditionally done different things
  • the latest standard actually forbids it

Time for Another Exercise!

(Yes!)

A Quick Aside on Arrays

An Array literal, assignment and the length property


const numbers = [1, 2, 3];
console.log(numbers[0]);
console.log(numbers.length);
// an empty array ... []

Max Number

Write a function that:

  • takes one parameter, an Array
  • assume that the Array will only 0 or more values that are of type, Number
  • the function should return the largest number in the Array
  • if the Array is empty, just return undefined