闭包用运。

闭包在JavaScript编程中有多种实用场景,以下列举几个常见的闭包使用场景并附上相应的代码示例:

不使用 new 关键字调用构造函数时,构造函数内部的 this 关键字会指向全局对象(在浏览器中通常是 window 对象)。此时,构造函数的返回值取决于函数体中的代码逻辑。如果函数体中没有显式地返回一个对象,则返回 undefined

function Counter() {
  let count = 0; // 私有变量
  const aaa = () => {
    console.log(count);
    // return `1221`;
  };
  // 公共接口(闭包)
  return {
    bbb: function () {
      count++;
    },
    aaa: aaa, // 将aaa函数作为属性返回
  };
}
const counter = Counter();
counter.aaa(); // 0 只是执行了
console.log(counter.aaa(), "[["); //0 undefined  [[
// 执行后输出0, 并没有返回值输出undefined, 最后输出[[
console.log(counter.count); //undefined 私有变量,没有返回,无法直接访问
0
0 undefined [[
undefined

使用class来改造,很明显不需要return就可以访问

使用 new 关键字调用构造函数时,会创建一个新的对象,并将该对象作为 this 关键字的值传递给构造函数。然后构造函数会在这个新对象上添加属性和方法,并最终将该对象作为返回值返回。这样创建的对象是构造函数的一个实例,具有构造函数所定义的属性和方法。

class Counter {
  constructor() {
    this.count = 0; // 私有变量
  }

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }

  getCount() {
    return this.count;
  }
}

const counterInstance = new Counter();
counterInstance.increment();
console.log(counterInstance.getCount()); // 输出: 1

1. 模块化开发与私有变量封装

闭包可以用来模拟私有变量和方法,实现模块化的封装。外部代码无法直接访问到闭包内部的变量,只能通过提供的公共接口进行交互。

function Counter() {
  let count = 0; // 私有变量

  // 公共接口(闭包)
  return {
    increment: function () {
      count++;
    },
    decrement: function () {
      count--;
    },
    getCount: function () {
      return count;
    },
  };
}

const counterInstance = Counter();
counterInstance.increment();
console.log(counterInstance.getCount()); // 输出: 1

下面是soybean-admin自己封装的useBoolean:

import { ref } from 'vue';

/**
 * boolean组合式函数
 * @param initValue 初始值
 */
export default function useBoolean(initValue = false) {
  const bool = ref(initValue);

  function setBool(value: boolean) {
    bool.value = value;
  }
  function setTrue() {
    setBool(true);
  }
  function setFalse() {
    setBool(false);
  }
  function toggle() {
    setBool(!bool.value);
  }

  return {
    bool,
    setBool,
    setTrue,
    setFalse,
    toggle
  };
}

2. 延长变量生命周期

闭包可以保持对外部函数作用域中变量的引用,即使外部函数已经执行完毕,这些变量也不会被垃圾回收机制回收,从而延长了它们的生命周期。

function createMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); // 输出: 10
console.log(triple(5)); // 输出: 15

在这个例子中,createMultiplier 函数虽然已经执行完毕,但其内部创建的闭包(返回的匿名函数)仍然保持着对外部函数参数 factor 的引用,因此 double 和 triple 分别保留了不同的乘数因子。

3. setTimeout、setInterval 中的异步操作与传参

原生的 setTimeout 和 setInterval 函数不能直接捕获外部作用域中的变量,通过闭包可以解决这个问题,确保回调函数访问到正确的变量值。

function delayedAlert(message, delay) {
  setTimeout(function() {
    alert(message);
  }, delay);
}

let user = "John";
delayedAlert(user + " will see this alert in 2 seconds.", 2000);

// 即使在这之后 user 变量被改变,延迟的 alert 仍显示原始值
user = "Jane";

4. 事件监听器与回调函数

在处理事件绑定或异步操作时,闭包有助于确保回调函数能够访问到正确的上下文数据。

function attachEventHandlers(elements, eventName, handlerCreator) {
  elements.forEach((element) => {
    element.addEventListener(eventName, handlerCreator(element));
  });
}

const buttons = document.querySelectorAll('button');
const logButtonId = function(button) {
  return function(event) {
    console.log(`Clicked button with id: ${button.id}`);
  };
};

attachEventHandlers(buttons, 'click', logButtonId);

在这个例子中,每个按钮的点击事件处理器(闭包)都绑定了对应的按钮元素,即使所有处理器共享同一个事件处理逻辑(logButtonId 函数),也能正确地输出各自按钮的 ID。

5. 遍历数组或其他集合时的迭代状态

闭包可以用于记录迭代过程中的状态,特别是在使用高阶函数(如 Array.prototype.mapArray.prototype.reduce)时。

function getRunningTotal(numbers) {
  return numbers.map((num, index, arr) => {
    const currentSum = arr.slice(0, index + 1).reduce((acc, val) => acc + val, 0);
    return { value: num, runningTotal: currentSum };
  });
}

const numbers = [1, 2, 3, 4, 5];
const result = getRunningTotal(numbers);
console.log(result); // 输出: [{ value: 1, runningTotal: 1 }, { value: 2, runningTotal: 3 }, ...]

以上代码展示了如何使用闭包来计算数组中每个元素到当前位置的累计和,闭包在 map 函数的回调中捕获并维护了当前的累计值。

这些代码示例展示了闭包在不同场景下的应用,包括模块化、变量生命周期管理、异步操作、事件处理以及状态跟踪等。闭包的核心价值在于它能捕获并保持对外部作用域的访问,提供了一种灵活且安全的方式来组织和控制代码中的数据访问。

相关推荐

  1. 2024-04-12 10:10:02       43 阅读
  2. 9、python-

    2024-04-12 10:10:02       62 阅读
  3. 关于Golang

    2024-04-12 10:10:02       56 阅读
  4. Rust

    2024-04-12 10:10:02       56 阅读
  5. Python

    2024-04-12 10:10:02       56 阅读
  6. 如何理解

    2024-04-12 10:10:02       47 阅读
  7. Python

    2024-04-12 10:10:02       44 阅读
  8. Python:

    2024-04-12 10:10:02       45 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-12 10:10:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-12 10:10:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-12 10:10:02       82 阅读
  4. Python语言-面向对象

    2024-04-12 10:10:02       91 阅读

热门阅读

  1. node.js 常用命令大全

    2024-04-12 10:10:02       44 阅读
  2. 计算机视觉介绍

    2024-04-12 10:10:02       143 阅读
  3. 三种语言实现spark createDataFrame

    2024-04-12 10:10:02       139 阅读
  4. vue 项目中添加DES加密

    2024-04-12 10:10:02       192 阅读
  5. C# 多维数组

    2024-04-12 10:10:02       161 阅读
  6. tcp三次握手四次挥手

    2024-04-12 10:10:02       38 阅读
  7. python如何判断图片为黑白还是彩色

    2024-04-12 10:10:02       33 阅读
  8. 4-10 面经

    2024-04-12 10:10:02       31 阅读
  9. 记录kafka-flink-kafka的end-to-end的exactly-once语义

    2024-04-12 10:10:02       37 阅读