函数
定义函数
函数提升仅适用于函数声明,而不适用于函数表达式
函数声明
函数表达式
//例子1
const factorial = function fac(n) {return n < 2 ? 1 : n * fac(n - 1);
};console.log(factorial(3)); // 6
//factorial(n)、fac(n)、arguments.callee()
-------------------------------------------
//例子2 该函数接收由函数表达式定义的函数,并对作为第二个参数接收的数组的每个元素执行该函数:
function map(f, a) {const result = new Array(a.length);for (let i = 0; i < a.length; i++) {result[i] = f(a[i]);}return result;
}const cube = function (x) {return x * x * x;
};const numbers = [0, 1, 2, 5, 10];
console.log(map(cube, numbers)); // [0, 1, 8, 125, 1000]
递归
function foo(i) {if (i < 0) {return;}console.log(`开始:${i}`);foo(i - 1);console.log(`结束:${i}`);
}
foo(3);// 打印:
// 开始:3
// 开始:2
// 开始:1
// 开始:0
// 结束:0
// 结束:1
// 结束:2
// 结束:3
用于获取DOM树子节点
function walkTree(node) {if (node === null) {return;}// 对节点做些什么for (let i = 0; i < node.childNodes.length; i++) {walkTree(node.childNodes[i]);}
}
闭包
闭包在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。闭包是可以拥有独立变量以及绑定了这些变量的环境(“封闭”了表达式)的表达式(通常是函数)。既然嵌套函数是一个闭包,就意味着一个嵌套函数可以“继承”容器函数的参数和变量。换句话说,内部函数包含外部函数的作用域。
闭包是 JavaScript 中最强大的特性之一。JavaScript 允许函数嵌套,并且内部函数具有定义在外部函数中的所有变量和函数(以及外部函数能访问的所有变量和函数)的完全访问权限。
外部函数却不能访问定义在内部函数中的变量和函数。这给内部函数的变量提供了一种封装。
此外,由于内部函数可以访问外部函数的作用域,因此当内部函数生存周期大于外部函数时,外部函数中定义的变量和函数的生存周期将比内部函数执行的持续时间要长。当内部函数以某一种方式被任何一个外部函数之外的任何作用域访问时,就会创建闭包。
- 内部函数只可以在外部函数中访问。
- 内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。
function addSquares(a, b) {function square(x) {return x * x;}return square(a) + square(b);
}console.log(addSquares(2, 3)); // 13
console.log(addSquares(3, 4)); // 25
console.log(addSquares(4, 5)); // 41
--------------------------------------
//由于内部函数形成了闭包,因此你可以调用外部函数并为外部函数和内部函数指定参数:
function outside(x) {function inside(y) {return x + y;}return inside;
}const fnInside = outside(3); // 可以这样想:给我一个可以将提供的值加上 3 的函数
console.log(fnInside(5)); // 8
console.log(outside(3)(5)); // 8
保存变量:上例中
inside
被返回时x
是怎么被保留下来的。一个闭包必须保存它可见作用域中所有参数和变量。因为每一次调用传入的参数都可能不同,每一次对外部函数的调用实际上重新创建了一遍这个闭包。只有当返回的inside
没有再被引用时,内存才会被释放。
多层嵌套函数
- 函数(
A
)可以包含函数(B
),后者可以再包含函数(C
)。 - 这里的函数
B
和C
都形成了闭包,所以B
可以访问A
,C
可以访问B
。 - 此外,因为
C
可以访问B
(而B
可以访问A
),所以C
也可以访问A
。
闭包可以包含多个作用域;它们递归地包含了所有包含它的函数作用域。这个称之为作用域链
function A(x) {function B(y) {function C(z) {console.log(x + y + z);}C(3);}B(2);
}
A(1); // 打印 6(即 1 + 2 + 3)
------------------------------------
//实例2
function outside() {const x = 5;function inside(x) {return x * 2;}return inside;
}
console.log(outside()(10)); // 20(而不是 10)//这里的作用链域是 {inside、outside、全局对象}。因此 inside 的 x 优先于 outside 的 x