往期回顾
记忆函数
JavaScript 中的记忆函数(Memoization)是一种优化技术,用于提高函数的效率。它的基本思想是存储昂贵的函数调用结果,当再次以相同的参数调用该函数时,可以直接返回存储的结果,避免不必要的计算。
在 JavaScript 中,记忆函数通常通过闭包来实现。闭包可以访问其词法作用域,即使函数在其词法作用域之外执行。这意味着,闭包可以记住并访问创建它时作用域中的变量。利用这个特性,我们可以创建一个函数,它记住了为给定参数执行原始函数的结果。
下面是一个简单的记忆函数的实现:
function memoize(func) {
let cache = {};
return function(...args) {
// 将参数转换为字符串,作为缓存的键
const key = JSON.stringify(args);
// 如果结果已经在缓存中,则直接返回缓存的结果
if (cache[key]) {
return cache[key];
}
// 否则,调用原始函数,并将结果存储在缓存中
const result = func.apply(this, args);
cache[key] = result;
return result;
};
}
使用时,只需将要记忆化的函数作为参数传递给 memoize 函数。例如:
function expensiveComputation(num) {
// 模拟一个耗时的计算
console.log(`计算 ${num}`);
return num * num;
}
const memoizedFunction = memoize(expensiveComputation);
memoizedFunction(4); // 计算并缓存结果
memoizedFunction(4); // 直接返回缓存的结果,不进行计算
在上述示例中,首次调用 memoizedFunction(4) 时,会进行计算并缓存结果。当再次以相同的参数调用 memoizedFunction(4) 时,由于结果已经在缓存中,函数将直接返回缓存的结果,而不会进行重复的计算。
记忆函数在处理大量数据或频繁调用函数的情况下非常有用,例如在处理大型数据集、频繁的API调用或复杂的算法时。通过记忆化,可以显著提高应用程序的性能和响应速度。
闭包
JavaScript 中的闭包是一个非常强大且核心的特性,它允许函数记住并访问其词法作用域,即使函数在其词法作用域之外执行。闭包可以让你保存状态——即,它们可以记住并访问创建它们时作用域中的变量,上面的记忆函数就是靠闭包实现的。下面通过一些例子来详细解释闭包的概念。
闭包的基本例子
function createCounter() {
let count = 0;
return function() {
// 这里的匿名函数就是闭包,它能够访问上层函数作用域中的变量count
count += 1;
return count;
};
}
const counter = createCounter(); // 调用createCounter时,会创建一个闭包
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
在这个例子中,createCounter 函数返回了一个匿名函数,这个匿名函数可以访问并修改外部函数 createCounter 的局部变量 count。即使 createCounter 的执行上下文已经消失,返回的函数仍然可以访问 count 变量,这是因为闭包。
当调用 createCounter() 时,JavaScript 会为 createCounter 创建一个执行上下文,在这个上下文中,let count = 0; 被执行一次,创建一个 count 变量,并将其初始值设置为 0。然后,createCounter 函数返回一个匿名函数,这个匿名函数就是一个闭包,它能够访问 createCounter 函数作用域中的 count 变量。
当调用 counter() 时,实际上是调用了 createCounter 返回的那个匿名函数。这个匿名函数执行时,它的执行上下文是 createCounter 的执行上下文,因此它能够访问 createCounter 作用域中的 count 变量。每次调用 counter() 时,都会访问同一个 count 变量,因此 count 的值会在每次调用之间共享。
闭包的持久性
闭包的持久性意味着闭包中的变量会一直保持在内存中,这既是闭包的优势也是它的缺点(可能导致内存泄漏)。
function makeAdder(x) {
return function(y) {
return x + y;
};
}
const add5 = makeAdder(5);
console.log(add5(10)); // 输出:15
// 即使makeAdder的执行上下文已经消失,x仍然被保留在内存中
总结
记忆函数和闭包是 JavaScript 中非常强大和实用的特性。记忆函数通过闭包实现,可以避免重复计算,提高程序的性能和响应速度,尤其在处理大量数据或频繁调用函数的情况下非常有用。闭包则可以让函数记住并访问其词法作用域,即使函数在其词法作用域之外执行,这一特性为 JavaScript 的函数编程提供了极大的灵活性和表达能力。理解和掌握这两个概念,对于深入学习和应用 JavaScript 来说非常重要。