[JavaScript] 闭包

闭包概念

闭包(Closure)是 JavaScript 中的一个核心概念,它指的是函数和其外部环境(或词法作用域)之间的组合。简单来说,闭包是指当一个函数在其外部作用域中引用了变量时,该函数和这些变量的组合形成了一个闭包

闭包的表现

闭包通常是由一个外部函数包裹一个内部函数,且返回内部函数,从而使得内部函数可以访问外部函数作用域中的变量。但这并不是闭包的唯一形式。

闭包的本质是 函数“记住”了它所在的词法作用域,即使这个函数是在其定义的作用域之外执行的。

常见的闭包

function outerFunction() {
    let count = 0;
    return function innerFunction() {
        count++;
        console.log(count);
    };
}

const closure = outerFunction();
closure(); // 输出 1
closure(); // 输出 2

不返回函数的闭包

即使外部函数不返回内部函数,闭包仍然存在,只要内部函数访问了外部函数中的变量。例如,在事件监听器或定时器中。

function setupClickListener() {
    let count = 0;
    document.getElementById('myButton').addEventListener('click', function() {
        count++;
        console.log(count); // 访问了外部函数的变量 count
    });
}

setupClickListener();

虽然 setupClickListener 没有返回内部函数,但内部函数仍然形成了闭包,因为它引用了外部函数中的 count 变量。

定时器中的闭包

function startTimer() {
    let count = 0;
    setInterval(function() {
        count++;
        console.log(count); // 访问外部函数的 count
    }, 1000);
}

startTimer();

使用场景

数据封装

闭包允许创建私有变量,这些变量在函数外部无法直接访问。通过闭包,可以创建具有私有状态的对象,从而实现数据封装。例如:

function createCounter() {
  let count = 0; // count 是私有变量
  return function () {
    count++;
    return count;
  };
}

const counter1 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2

const counter2 = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

闭包可以用来创建模块化的代码结构,使得模块内的变量和函数不会污染全局命名空间。例如:

const Module = (function () {
  let privateVar = "I am private";

  function privateMethod() {
    console.log(privateVar);
  }

  return {
    publicMethod: function () {
      privateMethod();
    }
  };
})();

Module.publicMethod(); // 输出 "I am private"

闭包的关键在于它能够“记住”外部函数的状态,即使外部函数已经执行完毕。这个特性使得闭包在 JavaScript 中非常有用,尤其是在涉及到数据隐私、状态管理和函数工厂等方面。

延迟执行

闭包可以用来延迟执行某些代码,尤其在处理异步操作时。例如:

function delayedGreeting(name) {
  return function () {
    console.log(`Hello, ${name}!`);
  };
}

const greetJohn = delayedGreeting("John");
setTimeout(greetJohn, 1000); // 1秒后输出 "Hello, John!"

事件处理

闭包常用于事件处理程序,以便访问事件处理程序内的数据。例如:

function setupButton(buttonId) {
  const button = document.getElementById(buttonId);
  let count = 0;

  button.addEventListener("click", function () {
    count++;
    console.log(`Button clicked ${count} times`);
  });
}

setupButton("myButton");

内存泄漏

闭包可以导致内存泄漏,因为闭包会保留对其外部作用域的引用。如果闭包引用的变量或函数没有被及时释放,垃圾回收机制可能不会回收这些内存,从而导致内存泄漏。

例如,在事件监听器中使用闭包,如果不及时移除事件监听器,可能会导致内存无法被释放:

function createListener() {
    let element = document.getElementById('myElement');
    element.addEventListener('click', function() {
        console.log('Clicked!');
    });
}
createListener();

这个例子中,如果不手动移除事件监听器,即使元素被删除了,闭包仍然会保留对它的引用,导致内存泄漏。

避免过度依赖闭包来保存状态

可以通过将状态和逻辑分离来减少闭包的使用。例如,使用对象、类或者数据结构来管理状态,而不是全部放入闭包中。

class Counter {
    constructor() {
        this.count = 0;
    }

    increment() {
        this.count++;
        return this.count;
    }
}

const counter = new Counter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
posted @   Himmelbleu  阅读(12)  评论(0编辑  收藏  举报
历史上的今天:
2023-08-30 TS - Vite 配置了路径别名还是提示模块未找到
2023-08-30 Node.js - path.resolve(__dirname, "/src") 无法拼接绝对地址
首页
随笔
博客园
我的
标签
管理
[JavaScript] 闭包
发表于 2024-08-30 19:40
|
已有 12 人阅读
|
留下 0 条评论
|
全文字数 ≈ 676字

闭包概念

闭包(Closure)是 JavaScript 中的一个核心概念,它指的是函数和其外部环境(或词法作用域)之间的组合。简单来说,闭包是指当一个函数在其外部作用域中引用了变量时,该函数和这些变量的组合形成了一个闭包

闭包的表现

闭包通常是由一个外部函数包裹一个内部函数,且返回内部函数,从而使得内部函数可以访问外部函数作用域中的变量。但这并不是闭包的唯一形式。

闭包的本质是 函数“记住”了它所在的词法作用域,即使这个函数是在其定义的作用域之外执行的。

常见的闭包

JS
function outerFunction() {
    let count = 0;
    return function innerFunction() {
        count++;
        console.log(count);
    };
}

const closure = outerFunction();
closure(); // 输出 1
closure(); // 输出 2

不返回函数的闭包

即使外部函数不返回内部函数,闭包仍然存在,只要内部函数访问了外部函数中的变量。例如,在事件监听器或定时器中。

JS
function setupClickListener() {
    let count = 0;
    document.getElementById('myButton').addEventListener('click', function() {
        count++;
        console.log(count); // 访问了外部函数的变量 count
    });
}

setupClickListener();

虽然 setupClickListener 没有返回内部函数,但内部函数仍然形成了闭包,因为它引用了外部函数中的 count 变量。

定时器中的闭包

JS
function startTimer() {
    let count = 0;
    setInterval(function() {
        count++;
        console.log(count); // 访问外部函数的 count
    }, 1000);
}

startTimer();

使用场景

数据封装

闭包允许创建私有变量,这些变量在函数外部无法直接访问。通过闭包,可以创建具有私有状态的对象,从而实现数据封装。例如:

JAVASCRIPT
function createCounter() {
  let count = 0; // count 是私有变量
  return function () {
    count++;
    return count;
  };
}

const counter1 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2

const counter2 = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

闭包可以用来创建模块化的代码结构,使得模块内的变量和函数不会污染全局命名空间。例如:

JAVASCRIPT
const Module = (function () {
  let privateVar = "I am private";

  function privateMethod() {
    console.log(privateVar);
  }

  return {
    publicMethod: function () {
      privateMethod();
    }
  };
})();

Module.publicMethod(); // 输出 "I am private"

闭包的关键在于它能够“记住”外部函数的状态,即使外部函数已经执行完毕。这个特性使得闭包在 JavaScript 中非常有用,尤其是在涉及到数据隐私、状态管理和函数工厂等方面。

延迟执行

闭包可以用来延迟执行某些代码,尤其在处理异步操作时。例如:

JAVASCRIPT
function delayedGreeting(name) {
  return function () {
    console.log(`Hello, ${name}!`);
  };
}

const greetJohn = delayedGreeting("John");
setTimeout(greetJohn, 1000); // 1秒后输出 "Hello, John!"

事件处理

闭包常用于事件处理程序,以便访问事件处理程序内的数据。例如:

JAVASCRIPT
function setupButton(buttonId) {
  const button = document.getElementById(buttonId);
  let count = 0;

  button.addEventListener("click", function () {
    count++;
    console.log(`Button clicked ${count} times`);
  });
}

setupButton("myButton");

内存泄漏

闭包可以导致内存泄漏,因为闭包会保留对其外部作用域的引用。如果闭包引用的变量或函数没有被及时释放,垃圾回收机制可能不会回收这些内存,从而导致内存泄漏。

例如,在事件监听器中使用闭包,如果不及时移除事件监听器,可能会导致内存无法被释放:

JAVASCRIPT
function createListener() {
    let element = document.getElementById('myElement');
    element.addEventListener('click', function() {
        console.log('Clicked!');
    });
}
createListener();

这个例子中,如果不手动移除事件监听器,即使元素被删除了,闭包仍然会保留对它的引用,导致内存泄漏。

避免过度依赖闭包来保存状态

可以通过将状态和逻辑分离来减少闭包的使用。例如,使用对象、类或者数据结构来管理状态,而不是全部放入闭包中。

JS
class Counter {
    constructor() {
        this.count = 0;
    }

    increment() {
        this.count++;
        return this.count;
    }
}

const counter = new Counter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
作者:Himmelbleu
出处: https://www.cnblogs.com/Himmelbleu/#/p/18389388
版权:本作品采用「 署名-非商业性使用-相同方式共享 4.0 国际 」许可协议进行许可。
文章目录
闭包概念
闭包的表现
常见的闭包
不返回函数的闭包
定时器中的闭包
使用场景
数据封装
延迟执行
事件处理
内存泄漏
避免过度依赖闭包来保存状态
点击右上角即可分享
微信分享提示