Javascript详细闭包知识点指南

闭包 (Closure)是JavaScript中一个重要而强大的概念。它是指在一个函数内部定义的函数,它可以访问外部函数的变量 ,即使外部函数已经执行完毕。闭包使得函数内的变量在函数执行完后仍然可以被访问,这种机制有助于实现封装、模块化和函数式编程。

开始

  1. 定义: 闭包是指一个函数可以访问其包含函数(外部函数)中定义的变量,即使在外部函数执行完毕后。
  2. 创建闭包: 闭包通常在一个函数内部定义另一个函数,并将内部函数作为返回值。当内部函数被返回时,它仍然可以访问外部函数的变量。
js 复制代码
function outerFunction() {
  let outerVariable = 'I am from outer function';
  
  function innerFunction() {
    console.log(outerVariable);
  }
  
  return innerFunction;
}

const closureExample = outerFunction();
closureExample(); // 输出:I am from outer function
  1. 访问外部变量: 内部函数可以访问外部函数的参数和局部变量,甚至可以访问外部函数返回的其他函数。
js 复制代码
function outerFunction(x) {
  function innerFunction(y) {
    console.log(x + y);
  }
  return innerFunction;
}

const closureExample = outerFunction(5);
closureExample(3); // 输出:8
  1. 保持状态: 闭包可以用于保持状态,因为它们可以访问外部函数的变量,并且这些变量在外部函数执行后不会被销毁。
js 复制代码
function counter() {
  let count = 0;
  return function() {
    count++;
    console.log(count);
  };
}

const increment = counter();
increment(); // 输出:1
increment(); // 输出:2
  1. 实现私有变量: 闭包可以用于实现私有变量,因为内部函数可以访问外部函数的变量,但外部无法直接访问内部函数的变量。
js 复制代码
function createPerson(name) {
  let privateName = name;
  return {
    getName: function() {
      return privateName;
    }
  };
}
const person = createPerson('John');
console.log(person.getName()); // 输出:John

涉及的其他相关高级知识点

1. this 关键字与闭包

在 JavaScript 中,this 关键字的值在函数被调用时确定。在闭包中,this 的值可能会引起一些意外行为,因为它取决于函数的调用方式。

示例:

js 复制代码
function Counter() {
  this.count = 0;

  setInterval(function() {
    // 在此处的 this 指向全局对象而不是 Counter 实例
    this.count++;
    console.log(this.count);
  }, 1000);
}

const counter = new Counter();
// 输出 NaN(因为全局对象没有 count 属性)

解决方法:

  • 使用额外的变量 self 来捕获正确的 this 值。
  • 使用箭头函数,因为箭头函数没有自己的 this,它会继承自外部作用域。
js 复制代码
function Counter() {
  this.count = 0;

  // 使用额外的变量 self 解决
  var self = this;
  setInterval(function() {
    self.count++;
    console.log(self.count);
  }, 1000);
}

// 或者使用箭头函数
function Counter() {
  this.count = 0;

  setInterval(() => {
    this.count++;
    console.log(this.count);
  }, 1000);
}

2. 作用域链

作用域链是指在 JavaScript 中,每个函数都有一个与之相关联的作用域链,用于查找变量。闭包通过作用域链实现对外部变量的引用。

示例:

js 复制代码
function outer() {
  let outerVar = 'I am outer';

  function inner() {
    console.log(outerVar); // 内部函数可以访问外部函数的变量
  }

  inner();
}

outer(); // 输出:I am outer

3. 循环中的闭包

在循环中使用闭包时,需要注意循环变量在闭包中的值可能不是你期望的值,因为闭包捕获的是变量的引用,而不是值。 示例:

js 复制代码
for (var i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i); // 输出 6(循环结束后的值)
  }, i * 1000);
}
  • 解决方法: 使用立即执行函数表达式(IIFE)来捕获正确的循环变量值。
js 复制代码
for (var i = 1; i <= 5; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j);
    }, j * 1000);
  })(i);
}

4. 内存管理与解除引用 (内存泄漏问题)

闭包可能导致内存泄漏,因为它们可以长时间保留对外部函数作用域中变量的引用,阻止这些变量被垃圾回收。

示例:

js 复制代码
function createClosure() {
  let data = new Array(1000000).fill('Some data');

  return function() {
    console.log(data.length);
  };
}

const leakyClosure = createClosure();
leakyClosure(); // 在这里使用闭包

// 在不需要时解除对闭包的引用
// leakyClosure = null;

如果不解除对 leakyClosure 的引用,data 数组将一直存在于内存中,即使它不再被需要。解除引用后,垃圾回收器将能够回收这些不再使用的资源

5. 使用闭包实现模块模式

闭包可以用于创建私有变量和方法,从而实现模块化的代码结构。这种方式可以隐藏实现细节,防止全局命名空间的污染。

js 复制代码
const myModule = (function() {
  let privateVariable = 'I am private';

  function privateFunction() {
    console.log('This is private');
  }

  return {
    publicVariable: 'I am public',
    publicFunction: function() {
      console.log('This is public');
      privateFunction();
    }
  };
})();

console.log(myModule.publicVariable); // I am public
myModule.publicFunction(); 
// This is public  
// This is private

完~

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax