JavaScript——对闭包的看法,为什么要用闭包?说一下闭包原理以及应用场景

简介: JavaScript——对闭包的看法,为什么要用闭包?说一下闭包原理以及应用场景

前言

  • 闭包是什么
  • 闭包原理是什么
  • 闭包优缺点
  • 闭包应用场景

步骤

1)什么是闭包

函数执行后返回结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,即形成了闭包。

可以在内部函数访问到外部函数作用域。使用闭包,一可以读取函数中的变量,二可以将函数中的变量存储在内存中,保护变量不被污染。而正因闭包会把函数中的变量值存储在内存中,会对内存有消耗,所以不能滥用闭包,否则会影响网页性能,造成内存泄漏。当不需要使用闭包时,要及时释放内存,可将内层函数对象的变量赋值为null。

可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员

示例:

function makeFn() {
  let msg = 'hello fn'
  return function () {
    console.log(msg)
  }
}
const fn = makeFn()
fn()
// fn() 调用了makeFn内部的内部函数function并访问到了makeFn作用域中的成员msg,这就形成了闭包

2)闭包原理

函数执行分成两个阶段(预编译阶段和执行阶段)。

  • 在预编译阶段,如果发现内部函数使用了外部函数的变量,则会在内存中创建一个“闭包”对象并保存对应变量值,如果已存在“闭包”,则只需要增加对应属性值即可。
  • 执行完后,函数执行上下文会被销毁,函数对“闭包”对象的引用也会被销毁,但其内部函数还持用该“闭包”的引用,所以内部函数可以继续使用“外部函数”中的变量

利用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕,其执行作用域链销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被烧毁后才被销毁。

3)优点

  1. 可以从内部函数访问外部函数的作用域中的变量,且访问到的变量长期驻扎在内存中,可供之后使用
  2. 避免变量污染全局
  3. 把变量存到独立的作用域,作为私有成员存在

4)缺点

  1. 对内存消耗有负面影响。因内部函数保存了对外部变量的引用,导致无法被垃圾回收,增大内存使用量,所以使用不当会导致内存泄漏
  2. 对处理速度具有负面影响。闭包的层级决定了引用的外部变量在查找时经过的作用域链长度
  3. 可能获取到意外的值(captured value)

4)应用场景

应用场景一: 典型应用是模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局。

var Yideng = (function () {
    // 这样声明为模块私有变量,外界无法直接访问
    var foo = 0;
    function Yideng() {}
    Yideng.prototype.bar = function bar() {
        return foo;
    };
    return Yideng;
}());

应用场景二: 在循环中创建闭包,防止取到意外的值。

如下代码,无论哪个元素触发事件,都会弹出 3。因为函数执行后引用的 i 是同一个,而 i 在循环结束后就是 3

for (var i = 0; i < 3; i++) {
    document.getElementById('id' + i).onfocus = function() {
      alert(i);
    };
}
//可用闭包解决
function makeCallback(num) {
  return function() {
    alert(num);
  };
}
for (var i = 0; i < 3; i++) {
    document.getElementById('id' + i).onfocus = makeCallback(i);
}

学无止境,谦卑而行.

目录
相关文章
|
5天前
|
前端开发 机器人 API
前端大模型入门(一):用 js+langchain 构建基于 LLM 的应用
本文介绍了大语言模型(LLM)的HTTP API流式调用机制及其在前端的实现方法。通过流式调用,服务器可以逐步发送生成的文本内容,前端则实时处理并展示这些数据块,从而提升用户体验和实时性。文章详细讲解了如何使用`fetch`发起流式请求、处理响应流数据、逐步更新界面、处理中断和错误,以及优化用户交互。流式调用特别适用于聊天机器人、搜索建议等应用场景,能够显著减少用户的等待时间,增强交互性。
|
5天前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理与实战
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理与实战
|
4天前
|
前端开发 JavaScript UED
JavaScript 中的函数防抖与节流详解及实用场景
在前端开发中,处理用户频繁触发的事件,如输入框的输入、按钮点击、窗口调整大小等,常常需要优化性能以减少无效操作。为此,函数防抖(debounce)和函数节流(throttle)是两种常见的性能优化手段。本文将详细介绍两者的区别与实现,并探讨它们的应用场景。
14 1
|
5天前
|
前端开发 JavaScript
深入理解JavaScript中的事件循环(Event Loop):从原理到实践
【10月更文挑战第12天】 深入理解JavaScript中的事件循环(Event Loop):从原理到实践
16 1
|
5天前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理、应用与代码演示
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理、应用与代码演示
|
6天前
|
监控 JavaScript 前端开发
深入了解Vue.js:构建现代前端应用的利器
【10月更文挑战第11天】深入了解Vue.js:构建现代前端应用的利器
10 0
|
6天前
|
前端开发 JavaScript 开发者
深入了解Webpack:现代JavaScript应用的打包利器
【10月更文挑战第11天】 深入了解Webpack:现代JavaScript应用的打包利器
|
JavaScript 前端开发 Java
《JS原理、方法与实践》- Javascript简介
《JS原理、方法与实践》- Javascript简介
98 0
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
83 2
|
3月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
102 4