2 - Functions As First-Class Objects
2 - Functions As First-Class Objects
are fundamental
Introduction
• In JavaScript, functions are first-class objects, or first-class
citizens.
• They coexist with, and can be treated like, any other JavaScript
object.
• They can be referenced by variables, declared with literals, and
even passed as function parameters.
• Functions are primary modular units of execution.
• Except for the global JavaScript code executed in the page-
building phase, all of the script code that we’ll write for our pages
will be within a function.
2
The Deal with Objects
• First, let’s see some of the operations we can use with objects.
• In JavaScript, objects enjoy certain capabilities:
1. Objects can be created via literals: {}
2. They can be assigned to variables, array entries, and properties
of other objects:
var obj = {}; //Assigns a new object to a variable
objArr.push({});//Adds a new object to an array
obj.data = {};//Assigns a new object as a
property of another object
3. They can be passed as arguments to functions:
function hide(obj){
obj.visibility = false;
}
hide({});
3
The Deal with Objects
4. They can be returned as values from functions:
function returnNewobj() {
return {};
}
4
Functions as First-class Objects
1. Created via literals
function newFunction() {}
2. Assigned to variables, array entries, and properties of other
objects
5
Functions as First-class Objects
4. Returned as values from functions
function returnNewFunction() {
return function(){};
}
6
Callback Functions
• Functions can be passed to functions as arguments.
• We pass a function as an argument to another function that
might, at a later point in application execution, call the passed-in
function.
• This is an example of a more general concept known as a
callback function.
• The term stems from the fact that we’re establishing a function
that other code will later “call back” at an appropriate point of
execution.
function useless(Callbackfn) {
return Callbackfn();
}
7
Callback Functions
8
Callback Functions
• Another way to write the same code:
10
Storing Functions
• In certain cases, we want to store collections of unique functions.
• For example, when we need to manage collections of callbacks
that should be invoked when a certain event occurs.
var store = {
nextId: 1,
cache: {},
add: function(fn) {
if (!fn.id) {
fn.id = this.nextId++;
this.cache[fn.id] = fn;
return true;
}
}
};
function ninja(){}
if(store.add(ninja)){console.log("Function was safely
added.");}
if(!store.add(ninja)){console.log("But it was only added
once.");}
11
Self-memoizing Functions
• When using function properties, we can give a function the ability
to modify itself.
• This technique can be used to remember previously computed
values, saving time during future computations.
• Memoization: the process of building a function that’s capable
of remembering its previously computed values.
• Whenever a function computes its result, we store that result
alongside the function arguments.
• In this way, when another invocation occurs for the same set of
arguments, we can return the previously stored result, instead of
calculating it anew.
• This can markedly increase performance by avoiding needless
complex computations that have already been performed.
12
Self-memoizing Functions
• Within the isPrime function, we start by checking whether the answers
property that we’ll use as a cache.
• Within this cache, we’ll store the computed answer (true or false) using
the argument value as the property key. If we find a cached answer, we
return it.
function isPrime(value){
if (!isPrime.answers){ isPrime.answers = {}; }
if (isPrime.answers[value] !== undefined) {
return isPrime.answers[value]; }
var prime = value !== 1; // 1 is not a prime
for (var i = 2; i < value; i++) {
if (value % i === 0) {
prime = false;
break;
}
}
return isPrime.answers[value] = prime;
}
assert(isPrime(5), "5 is prime!" );
assert(isPrime.answers[5], "The answer was cached!" ); 13
Self-memoizing Functions
• This approach has two major advantages:
1. The end user enjoys performance benefits for function calls asking
for a previously computed value.
2. It happens seamlessly and behind the scenes; neither the end user
nor the page author needs to perform any special requests or do
any extra initialization in order to make it all work.
• Also, its disadvantages may need to be weighed against its advantages:
1. Any sort of caching will certainly sacrifice memory in favor of
performance.
2. Purists may consider that caching is a concern that shouldn’t be
mixed with the business logic; a function or a method should do
one thing and do it well.
3. It’s difficult to load-test or measure the performance of an
algorithm such as this one, because our results depend on the
previous inputs to the function.
14
Defining functions
• Functions are declared with the function keyword.
• JavaScript provides a couple of ways to define functions:
15
Function Declarations and Function Expressions
• Function declarations:
16
Function Declarations and Function Expressions
• Function declarations:
function samurai() {
return "samurai here";
}
function ninja() {
function hiddenNinja() {
return "ninja here";
}
return hiddenNinja();
}
17
Function Declarations and Function Expressions
• Function expressions:
• Because functions are such fundamental constructs, JavaScript
enables us to treat them as any other expressions.
• So, just as we can use number literals, for example
18
Function Declarations and Function Expressions
• The function name is optional.
19
Function Declarations and Function Expressions
• Function declarations must have a name defined because they stand
on their own.
• Because one of the basic requirements for a function is that it has to be
invokable, we have to have a way to reference it, and the only way to
do this is through its name.
• Function expressions, on the other hand, are parts of other JavaScript
expressions, so we have alternative ways to invoke them.
• For example, if a function expression is assigned to a variable, we can
use that variable to invoke the function:
var doNothing = function(){};
doNothing();
function doSomething(action) {
action();
}
20
Immediate Functions
(function(){})(3);
21
Arrow Functions
• Arrow functions are a simplification of function expressions.
22
Arrow Functions
• Arrow functions are a simplification of function expressions.
23
Arrow Functions
• The arrow function definition starts with an optional comma-separated
list of parameter names.
• If there are no parameters, or more than one parameter, this list must
be enclosed within parentheses.
• But if we have only a single parameter, the parentheses are optional.
• This list of parameters is followed by a mandatory fat-arrow operator,
which tells us and the JavaScript engine that we’re dealing with an
arrow function.
• After the fat-arrow operator, we have two options. If it’s a simple
function, we put an expression there (a mathematical operation,
another function invocation, whatever), and the result of the function
invocation will be the value of that expression.
• For instance, our first arrow function example has the following arrow
function:
var greet = name => "Greetings " + name;
24
Arrow Functions
• In other cases, when our arrow functions aren’t that simple and require
more code, we can include a block of code after the arrow operator. For
example:
var greet = name => {
var helloString = 'Greetings ‘;
return helloString + name;
};
25
Arguments and Function Parameters
• When discussing functions, we often use the terms argument and
parameter almost interchangeably, as if they were more or less the
same thing. But now, let’s be more formal:
§ A parameter is a variable that we list as part of a function definition.
§ An argument is a value that we pass to the function when we invoke it.
26
Arguments and Function Parameters
• If we have a different number of arguments than parameters, no error
is raised.
• JavaScript is perfectly fine with this situation and deals with it in the
following way:
27
Default parameters
• Default parameters enable us to specify default parameter values that
will be used if no value is supplied during function invocation
• In other programming languages, this problem is most often solved
with function overloading (specifying additional functions with the
same name but a different set of parameters).
• Unfortunately, JavaScript doesn’t support function overloading.
• To get around this problem, JS offers default parameters:
function performAction(student, action = “studying"){
return student + " " + action;
}
performAction(“Ahmed")
• We can assign any values to default parameters: simple, primitive
values such as numbers or strings, but also complex types such as
objects, arrays, and even functions.
•
28
Default parameters
• The values are evaluated on each function call, from left to right, and
when assigning values to later default parameters, we can reference
previous parameters, as in the following:
29