javascript-definitive-guide/notes/chap8_functions.md

5.8 KiB

Chapter 8. Functions

Function = a block of JS code that's defined once but may be invoked multiple times.

  • argument: values provided by during invocation as function's parameters.
  • return value: computed by function using argument values
  • invocation context: value of this keyword for each invocation

Utilization of functions:

  • method of object: if function is assigned to a property of an obj.
  • When a function is invoked on an object (e.g. obj.method()), this object become invocation context (aka this) for the function
  • Constructor: function designed to initialize a new obj.

Function as first class citizen (object):

  • In JS, functions are obj. Hence, can be manipulated by programs
  • We can set properties on functions and invoke methods on them (i.e. pass function as parameter to method)

JS function definitions can be nested within other functions

8.1 Defining Functions

8.1.1 Function Declarations

Function declaration (函数声明) = function keyword + Identifier as function name + (param1, param2, ...) + {JS statements as function body}

  • return causes function to stop executing and return computed value to caller
  • if body has no return, value of function is undefined
// Print the name and value of each property of o.  Return undefined.
function printprops(o) {
    for(let p in o) {
        console.log(`${p}: ${o[p]}\n`);
    }
}

// Compute the distance between Cartesian points (x1,y1) and (x2,y2).
function distance(x1, y1, x2, y2) {
    let dx = x2 - x1;
    let dy = y2 - y1;
    return Math.sqrt(dx*dx + dy*dy);
}

// A recursive function (one that calls itself) that computes factorials
// Recall that x! is the product of x and all positive integers less than it.
function factorial(x) {
    if (x <= 1) return 1;
    return x * factorial(x-1);
}
  • Name of function (in function declaration) becomes a variable, whose value is function itself.
  • function declaration statements are "hoisted" (level up) to top of enclosing block.
    • All function in a JS block will be defined before JS interpreter start execution

8.1.2 Function Expressions

Multiple Function Expression e.g.

// This function expression defines a function that squares its argument.
// Note that we assign it to a variable
const square = function(x) { return x*x; };

// Function expressions can include names, which is useful for recursion.
const f = function fact(x) { if (x <= 1) return 1; else return x*fact(x-1); };

// Function expressions can also be used as arguments to other functions:
[3,2,1].sort(function(a,b) { return a-b; });

// Function expressions are sometimes defined and immediately invoked:
let tensquared = (function(x) {return x*x;}(10));

Function Expression (FE 函数表达式):

  • FE appear within context of a larger expression, or within statement
  • name of function in FE is optional. (e.g. 1st FE e.g. has no function name)
  • FE/FD declare variable:
    • How FD use variable: (follow e.g. in 8.1.1 function factorial(x)) declares a variable and assigns a function obj to it.
    • How FE use variable: developer can decide whether assign the newly defined function obj to a const or var, so we can refer to it mult-times later. (e.g. 3rd & 5th FE e.g. does not assign function obj to obj, and directly use it)
  • Good practice: assign FE to const to protect function obj.

FD vs. FE:

  • Function defined by FD: the func obj are created before the script get executed (i.e. hoisted), so we can call these functions from code that appears above FD.
  • Functions defined by FE DO NOT EXIST until FE are evaluated.
  • To invoke a function (either defined using FE/FD), JS must can refer to it, function defined by FE cannot be referred until it's assigned to a variable

8.1.3 Arrow Functions

In ES6, Arrow Function provide more compact function syntax. Use arrow => to separate function parameters from function body

Syntax of arrow function:

  • general form: comma-separated list of params in parentheses, followed by => arrow, followed by function body in curly braces
const func_var = (param1, param2) => { return param1 + param2; };
  • compact form (single return): if function body is a single return statement, omit return, semicolon, and curly braces
const func_var = (param1, param2) => param1 + param2;
  • compact form (1 param): if arrow func has only 1 param, omit ()
const func_var = param => param*param + 2*param;
  • compact form (no param): if arrow func has no param, () must be there
const constantFunc = () => 42;

Additional Syntax rules:

  • No newline btw (param) and arrow: it will create valid statement with other meaning (e.g. const polynomial = x)
  • {} must needed in body for single return statement: it will avoid syntactic ambiguity:
const f = x => { return { value: x }; };  // Good: f() returns an object
const g = x => ({ value: x });            // Good: g() returns an object
const h = x => { value: x };              // Bad: h() returns nothing
const i = x => { v: x, w: x };            // Bad: Syntax Error

Where to use arrow function?

It's like lambda function in Python, it's ideal to pass arrow function to another function

// Make a copy of an array with null elements removed.
let filtered = [1,null,2,3].filter(x => x !== null); // filtered == [1,2,3]

Arrow Func vs other Funcs

  • Arrow func inherit value of this from the environment (where it's defined)
  • Arrow func do not have a prototype property, hence it cannot be used as constructor for new classes.

8.1.4 Nested Functions

function hypotenuse(a, b) {
    function square(x) { return x*x; }
    return Math.sqrt(square(a) + square(b));
}

Scoping rule of nested function: enclosure function can access param and var of the functions they are nested within (i.e. inner function know outer function's param)