Eloquent Javascript Chapter 3
Functions
Defining a function
// The variable square is being set to a function
// that has one parameter, x.
var square = function(x) { // Opening brace
return x * x; // Function body
}; // Closing brace
console.log(square(12));
// → 144
A function definition is just a regular variable definition where the value given to the variable happens to be a function.
A function starts with the keyword function, can have have a set of parameters and a body which is wrapped in curly braces {}.
Defining a function
var square = function(x) {
return x * x; // produce a value
};
console.log(square(12));
// → 144
var makeNoise = function() {
console.log("Pling!"); // side-effect
};
makeNoise();
// → Pling!
Some functions produce a value
while others produce a side effect.
A return statement determines the value the function returns and it immediately jumps out of the current function.
The return keyword without an expression after it will cause the function to return undefined.
Parameters and Scopes
Parameters to a function behave like regular variables, but their initial values are given by the caller of the function, not the code in the function itself
Variables created inside a function including their parameters, are local to the function.
This “localness” of variables applies only to the parameters and to variables declared with the var keyword
inside the function body.
Variables declared outside of any function are called global, and can be accessed anywhere.
var square = function(x) {
return x * x; // produce a value
};
console.log(square(12));
// → 144
Parameters and Scopes
var x = "outside";
var f1 = function() {
var x = "inside f1";
};
f1();
console.log(x);
// → outside
var f2 = function() {
x = "inside f2";
};
f2();
console.log(x);
// → inside f2
Nested Scope
var landscape = function() {
var result = "";
var flat = function(size) {
for (var count = 0; count < size; count++)
result += "_";
};
var mountain = function(size) {
result += "/";
for (var count = 0; count < size; count++)
result += "'";
result += "\\";
};
flat(3);
mountain(4);
flat(6);
mountain(1);
flat(1);
return result;
};
console.log(landscape());
// → ___/''''\______/'\_
Functions can be created inside other functions, producing several degrees of locality.
Functions as Values
Function variables usually simply act as names for a specific piece of the program. Such a variable is defined once and never changed. This makes it easy to start confusing the function and its name.
var func = function() {};
function variable: Left side of the equation.
function value: Right side of the equation.
Functions as Values
But the two are different. A function value can do all the things that other values can do—you can use it in arbitrary expressions, not just call it.
It is possible to store a function value in a new place, pass it as an argument to a function, and so on.
Similarly, a variable that holds a function is still just a regular variable and can be assigned a new value.
var launchMissiles = function(value) {
missileSystem.launch("now");
};
if (safeMode)
launchMissiles = function(value) {/* do nothing */};
Declaration Notation
The function keyword can also be used at the start of a statement.
function square(x) {
return x * x;
}
console.log("The future says:", future());
function future() {
return "We STILL have no flying cars.";
}
This is a function declaration
There is one subtlety with this form of
function definition.
The function is hoisted to the top of the scope.
Optional Arguments
alert("Hello", "Good Evening", "How do you do?");
The function alert officially accepts only one argument. When you call it like this, it doesn’t complain. It simply ignores the other arguments and shows you “Hello”.
JavaScript is extremely broad-minded about the number of arguments you pass to a function.
If you pass too many, the extra ones are ignored.
If you pass too few, the missing parameters simply get assigned the value undefined.
Optional Arguments
The upside:
This behavior can be used to have a function take “optional” arguments.
The downside:
It is possible—likely, even—that you’ll accidentally pass the wrong number of arguments to functions and no one will tell you about it.
Optional Arguments
function power(base, exponent) {
if (exponent == undefined)
exponent = 2;
var result = 1;
for (var count = 0; count < exponent; count++)
result *= base;
return result;
}
console.log(power(4));
// → 16
console.log(power(4, 3));
// → 64
power can be called either with two arguments or with a single argument,
in which case the exponent is assumed to be two, and the function behaves like square.
Closure
function wrapValue(n) {
var localVariable = n;
return function() { return localVariable; };
}
var wrap1 = wrapValue(1);
var wrap2 = wrapValue(2);
console.log(wrap1());
// → 1
console.log(wrap2());
// → 2
What happens to local variables when the function call that created them is no longer active?
This feature—being able to reference a specific instance of local variables in an enclosing function—is called closure.
A function that “closes over” some local variables is called a closure.
Closure
function multiplier(factor) {
return function(number) {
return number * factor;
};
}
var twice = multiplier(2);
console.log(twice(5));
// → 10
With a slight change, we can turn the previous example into a way to create functions that multiply by an arbitrary amount.
A good mental model is to think of the function keyword as “freezing” the code in its body and wrapping it into a package (the function value). So when you read return function(...) {...}, think of it as returning a handle to a piece of computation, frozen for later use.
Closure
var twice = multiplier(2);
// Step 1
function multiplier(2) {
return function(number) {
return number * 2;
};
}
console.log(twice(5));
// Step 1
var twice = function(number) {
return number * 2;
};
// Step 2
function(number) {
return number * 2;
}
// Step 3
function(5) {
return 5 * 2;
}
// → 10
Recursion
function power(base, exponent) {
if (exponent == 0)
return 1;
else
return base * power(base, exponent - 1);
}
console.log(power(2, 3));
// → 8
It is perfectly okay for a function to call itself,
as long as it takes care not to overflow the stack.
A function that calls itself is called recursive.
Recursion is a complicated concept and is best covered somewhere else.
Growing Functions
There are 2 general ways functions get added to a program.
- You find yourself writing similar code over and over again.
- You need functionality you haven't written yet and sounds like it should be it's own function.
How difficult it is to find a good name for a function is a good indication of how clear a concept it is that you’re trying to wrap.
How smart and versatile should our function be?
A useful principle is not to add cleverness unless you are absolutely sure you’re going to need it.
Functions and Side Effects
Functions can be roughly divided into types:
1)Those that are called for their side effects.
2)Those that are called for their return value.
console.log has the side affect of
printing something to the console.
A pure function is one that
given the same input will always return the same result.
Math.abs(-1) will always return 1
Pure functions are easy to test.
Summary
- The function keyword, when used as an expression, can create a function value.
-
When used as a statement, it can be used to declare a variable and give it a function as its value.
// Create a function value f
var f = function(a) {
console.log(a + 2);
};
// Declare g to be a function
function g(a, b) {
return a * b * 3.5;
}
Summary
- A key aspect in understanding functions is understanding local scopes.
- Parameters and variables declared inside a function are local to the function, re-created every time the function is called, and not visible from the outside.
- Functions declared inside another function have access to the outer function’s local scope.
Eloquent Javascript Chapter 3
By Dustin McCraw
Eloquent Javascript Chapter 3
- 1,605