深入理解JS的执行上下文、词法作用域和闭包(中)

简介: 深入理解JS的执行上下文、词法作用域和闭包(中)

三、闭包 🔒


闭包的定义和特点


闭包(Closure)是JavaScript中一种重要的概念,它指的是一个函数可以访问其词法作用域中的变量,即使这个函数在其词法作用域之外执行。闭包的主要特点有以下几点:


  1. 函数可以记住并访问其词法作用域:当一个函数在其词法作用域之外执行时,它仍然可以访问其词法作用域中的变量。

例如:

function foo() {
  let a = 1;
  function bar() {
    console.log(a); // 输出 1
  }
  bar();
}

foo();

在这个例子中,bar函数在其词法作用域foo之外执行,但仍然可以访问foo作用域中的变量a。


  1. 闭包可以让函数记住并访问其词法作用域,即使这个作用域在函数执行完毕后被销毁:当一个函数在其词法作用域之外执行时,即使这个作用域在函数执行完毕后被销毁,该函数仍然可以访问其词法作用域中的变量。

例如:

function createCounter() {
  let count = 0;
  return function() {
    count += 1;
    console.log(count); // 输出 1 2 3
  };
}

const counter = createCounter();
counter();
counter();
counter();

在这个例子中,createCounter函数返回一个闭包counter,每次调用counter时,它会访问其词法作用域createCounter中的变量count,即使createCounter函数执行完毕并销毁。


总结:闭包是JavaScript中一种重要的概念,它指的是一个函数可以访问其词法作用域中的变量,即使这个函数在其词法作用域之外执行。闭包的主要特点包括函数可以记住并访问其词法作用域,即使这个作用域在函数执行完毕后被销毁。理解闭包有助于更好地理解JavaScript中的变量作用域和函数调用等问题。


如何创建和使用闭包 🚀


闭包(Closure)是JavaScript中一种重要的概念,它指的是一个函数可以访问其词法作用域中的变量,即使这个函数在其词法作用域之外执行。下面介绍如何创建和使用闭包:


  1. 创建闭包:

在JavaScript中,闭包是由函数引用其词法作用域中的变量创建的。当一个函数在其词法作用域之外执行时,它仍然可以访问其词法作用域中的变量。


例如,下面的代码创建了一个闭包:

function foo() {
  let a = 1;
  function bar() {
    console.log(a); // 输出 1
  }
  bar();
}

foo();

在这个例子中,bar函数在其词法作用域foo之外执行,但仍然可以访问foo作用域中的变量a。


  1. 使用闭包:

闭包可以让函数记住并访问其词法作用域,即使这个作用域在函数执行完毕后被销毁。当一个函数在其词法作用域之外执行时,即使这个作用域在函数执行完毕后被销毁,该函数仍然可以访问其词法作用域中的变量。


例如,下面的代码使用了闭包:

function createCounter() {
  let count = 0;
  return function() {
    count += 1;
    console.log(count); // 输出 1 2 3
  };
}

const counter = createCounter();
counter();
counter();
counter();

在这个例子中,createCounter函数返回一个闭包counter,每次调用counter时,它会访问其词法作用域createCounter中的变量count,即使createCounter函数执行完毕并销毁。


总之,闭包是JavaScript中一种重要的概念,它指的是一个函数可以访问其词法作用域中的变量,即使这个函数在其词法作用域之外执行。创建闭包需要函数引用其词法作用域中的变量,使用闭包可以让函数记住并访问其词法作用域,即使这个作用域在函数执行完毕后被销毁。实际项目中,可以根据需求灵活地使用闭包。


闭包在实际编程中的应用场景 💡


闭包在实际编程中有很多应用场景,下面列举几个常见的例子:


  1. 模块化:闭包可以用来实现模块化,将一组相关的函数和变量封装在一个函数内部,然后返回这个函数的引用,这样就可以在其他地方调用这些函数并访问它们需要的变量。

例如,使用闭包实现一个简单的模块:

function createCart() {
  let products = [];

  function addProduct(product) {
    products.push(product);
  }

  function getProducts() {
    return products;
  }

  return {
    addProduct,
    getProducts
  };
}

const cart = createCart();
cart.addProduct({ id: 1, name: 'Product 1' });
console.log(cart.getProducts()); // 输出:[{ id: 1, name: 'Product 1' }]

在这个例子中,createCart函数返回一个闭包,包含addProductgetProducts函数以及它们需要的变量products


  1. 保持状态:闭包可以用来保持函数内部的状态,即使这个函数在其他地方执行。

例如,使用闭包实现一个简单的计数器:

function createCounter() {
  let count = 0;
  return function() {
    count += 1;
    console.log(count); // 输出 1 2 3
  };
}

const counter = createCounter();
counter();
counter();
counter();

在这个例子中,createCounter函数返回一个闭包,每次调用counter时,它会访问其词法作用域createCounter中的变量count,即使createCounter函数执行完毕并销毁。


  1. 实现柯里化(Currying):柯里化是一种将多参数函数转换为一系列使用一个参数的函数的技术。闭包可以让柯里化更加简洁和易读。

例如,使用闭包实现一个简单的柯里化函数:

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}

function sum(a, b, c) {
  return a + b + c;
}

const curriedSum = curry(sum);
const sum5 = curriedSum(5);
console.log(sum5(3)(2)); // 输出 10

在这个例子中,curry函数将一个多参数函数转换为一个闭包,这个闭包可以部分应用(即柯里化)。


总之,闭包在实际编程中有许多应用场景,包括模块化、保持状态、实现柯里化等。实际项目中,可以根据需求灵活地使用闭包。

相关文章
|
24天前
|
存储 JavaScript 前端开发
解释 JavaScript 中的作用域和作用域链的概念。
【4月更文挑战第4天】JavaScript作用域定义了变量和函数的可见范围,静态决定于编码时。每个函数作为对象拥有`scope`属性,关联运行期上下文集合。执行上下文在函数执行时创建,定义执行环境,每次调用函数都会生成独特上下文。作用域链是按层级组织的作用域集合,自内向外查找变量。变量查找遵循从当前执行上下文到全局上下文的顺序,若找不到则抛出异常。
21 6
|
24天前
|
JavaScript
闭包(js的问题)
闭包(js的问题)
12 0
|
1月前
|
设计模式 JavaScript 前端开发
js开发:请解释闭包(closure)是什么,以及它的用途。
闭包是JavaScript中的关键特性,允许函数访问并操作外部作用域的变量,常用于实现私有变量、模块化和高阶函数。私有变量示例展示了如何创建无法外部访问的计数器;模块化示例演示了封装私有变量和函数,防止全局污染;高阶函数示例则说明了如何使用闭包创建能接收或返回函数的函数。
16 2
|
1月前
|
存储 缓存 JavaScript
|
1天前
|
JavaScript 前端开发
js变量的作用域、作用域链、数据类型和转换应用案例
【4月更文挑战第27天】JavaScript 中变量有全局和局部作用域,全局变量在所有地方可访问,局部变量只限其定义的代码块。作用域链允许变量在当前块未定义时向上搜索父级作用域。语言支持多种数据类型,如字符串、数字、布尔值,可通过 `typeof` 检查类型。转换数据类型用 `parseInt` 或 `parseFloat`,将字符串转为数值。
6 1
|
3天前
|
测试技术
js_防抖与节流(闭包的使用)
js_防抖与节流(闭包的使用)
8 0
|
1月前
|
JavaScript 前端开发 Java
深入剖析 JavaScript 闭包
深入探讨JavaScript闭包,了解其定义、特性、优缺点及作用。闭包是函数与其引用环境的组合,允许内层函数访问外层作用域,常驻内存可能导致内存泄露。优点包括创建私有变量,缺点则涉及内存使用。闭包在变量搜索中遵循从内到外的规则,并影响变量的作用域和生存周期。理解闭包有助于优化代码并避免性能问题。
21 1
|
1月前
|
JavaScript 前端开发
js开发:请解释什么是作用域(scope),并说明全局作用域、局部作用域和块级作用域的区别。
JavaScript中的作用域规定了变量和函数的可见性与生命周期。全局作用域适用于整个脚本,变量可通过全局对象访问,可能导致命名冲突和内存占用。局部作用域限于函数内部,每次调用创建新作用域,执行完毕后销毁。ES6引入的块级作用域通过`let`和`const`实现,变量仅在其代码块内有效,并有暂时性死区。作用域机制有助于代码组织和变量管理。
23 1
|
1月前
|
自然语言处理 前端开发 JavaScript
深入理解JavaScript中的闭包与作用域链
在JavaScript编程中,闭包和作用域链是两个非常重要的概念,它们对于理解代码的执行过程和解决一些特定问题至关重要。本文将深入探讨JavaScript中闭包和作用域链的原理和应用,帮助读者更好地理解这些概念并能够在实际项目中灵活运用。
|
1月前
|
JavaScript 前端开发
JS作用域与作用域链
JS作用域与作用域链