当前位置: 首页 > news >正文

高性能网站建设指南 京东模拟网站开发

高性能网站建设指南 京东,模拟网站开发,中山建设厅网站,网站的seo 如何优化“爱自有天意,天有道自不会让有情人分离” 大家好,关于闭包问题其实实际上是js作用域的问题,那么js有几种作用域呢? 作用域类型关键字/场景作用域范围示例全局作用域var(无声明)整个程序var x 10;函数作用…

 “爱自有天意,天有道自不会让有情人分离”


大家好,关于闭包问题其实实际上是js作用域的问题,那么js有几种作用域呢?

作用域类型关键字/场景作用域范围示例
全局作用域var(无声明)整个程序var x = 10;
函数作用域var 在函数内函数内部function foo() { var x; }
块级作用域letconst{} 代码块内if (true) { let x; }
模块作用域ES6 模块单个模块文件export const x = 1;
词法作用域函数定义时定义时的外层作用域链闭包

我们常见的就是 全局作用域,函数作用域和块级作用域了。

闭包叫做词法作用域,我没听说过这个词,总而言之,闭包是一个作用域问题

 什么是闭包?​

闭包(Closure)是 JavaScript 中的一个核心概念,它指的是 ​​函数能够记住并访问其定义时的作用域(词法环境),即使该函数在其作用域之外执行​​。

用人话来讲就是:闭包是可以访问到另一个函数作用域中变量的函数 

在循环嵌套的函数结构中,闭包就很容易理解了。内部函数可以访问到外部函数中的变量,但是外部函数不能访问到内部函数中的变量。

我来举一个例子:
 


function outerFunction(outerParam) {// 外部函数的变量let outerVar = "我是外部变量";const outerConst = "我是外部常量";function innerFunction(innerParam) {// 内部函数的变量let innerVar = "我是内部变量";// 内部函数可以访问:// 1. 自己的变量console.log("内部函数访问自己的变量:", innerVar);console.log("内部函数访问自己的参数:", innerParam);// 2. 外部函数的变量和参数console.log("内部函数访问外部变量:", outerVar);console.log("内部函数访问外部常量:", outerConst);console.log("内部函数访问外部参数:", outerParam);return innerVar;}console.log("\n----- 分割线 -----\n");// 外部函数尝试访问内部函数的变量(会失败)console.log("外部函数可以访问自己的变量:", outerVar);console.log("外部函数可以访问自己的参数:", outerParam);// 下面这行如果取消注释会报错// console.log("外部函数无法访问内部变量:", innerVar); // ReferenceError: innerVar is not defined// 调用内部函数const result = innerFunction("内部参数");console.log("只能通过内部函数的返回值来获取内部变量:", result);return innerFunction;
}// 测试
const innerFn = outerFunction("外部参数");
console.log("\n----- 分割线 -----\n");
innerFn("新的内部参数");

输出结果:

----- 分割线 -----外部函数可以访问自己的变量: 我是外部变量
外部函数可以访问自己的参数: 外部参数
内部函数访问自己的变量: 我是内部变量
内部函数访问自己的参数: 内部参数
内部函数访问外部变量: 我是外部变量
内部函数访问外部常量: 我是外部常量
内部函数访问外部参数: 外部参数
只能通过内部函数的返回值来获取内部变量: 我是内部变量----- 分割线 -----内部函数访问自己的变量: 我是内部变量
内部函数访问自己的参数: 新的内部参数
内部函数访问外部变量: 我是外部变量
内部函数访问外部常量: 我是外部常量
内部函数访问外部参数: 外部参数

 这个代码展示的是:

  1. 内部函数可以访问:

    • 自己的变量(innerVar)和参数(innerParam)
    • 外部函数的变量(outerVar)、常量(outerConst)和参数(outerParam)
  2. 外部函数只能访问:

    • 自己的变量(outerVar)和参数(outerParam)
    • 无法直接访问内部函数的变量(innerVar)
    • 只能通过内部函数的返回值来间接获取内部变量的值

这就是所谓的"作用域链",内部函数可以向上访问外部作用域的变量,但外部作用域不能访问内部作用域的变量

闭包能干什么?

闭包能干的事情有:变量私有化回调函数函数柯里化。

变量私有化

什么是变量私有化?

变量私有化是一种编程技术,目的是​​限制变量的访问范围​​,使其只能在特定的作用域或模块内被访问和修改,外部代码无法直接操作。这样可以提高代码的安全性、可维护性,并减少命名冲突的风险。

通过闭包实现一下变量私有化

我们来做一个计数器案例,外部不能修改count,只能通过 increment() 和 getCount() 操作。

function createCounter() {let count = 0; // 私有变量,外部无法直接访问return {increment() {count++;},getCount() {return count;},};
}const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 1
console.log(count); // 报错:count is not defined(无法直接访问私有变量)

我们利用闭包创建了一个私有变量count,无法在外部访问,只有通过我们的increment() 和 getCount() 操作才能操作和访问。

回调函数

回调函数想必就不用介绍了,在任何语言中都有出现和应用。

闭包可以让回调函数记住并访问其定义时的作用域变量,即使回调在异步操作(如 setTimeoutfetch、事件监听)中被调用。

介绍一个例子:

setTimeout 回调​

​问题​​:直接使用循环变量 i 会导致所有回调输出相同的值(var 没有块级作用域)。
​解决​​:用闭包保存每次循环的 i 值。

// ❌ 错误写法(输出 3 个 3)
for (var i = 0; i < 3; i++) {setTimeout(function() {console.log(i); // 输出 3, 3, 3}, 100);
}// ✅ 正确写法(闭包保存 i 的值)
for (var i = 0; i < 3; i++) {(function(j) { // 立即执行函数(IIFE)创建闭包setTimeout(function() {console.log(j); // 输出 0, 1, 2}, 100);})(i); // 传入当前 i 的值
}

监听事件中的闭包

function setupButtons() {const buttons = document.querySelectorAll('button');for (var i = 0; i < buttons.length; i++) {(function(index) { // 闭包保存当前按钮的索引let count = 0; // 每个按钮独立的计数器buttons[index].addEventListener('click', function() {count++;console.log(`按钮 ${index} 被点击了 ${count} 次`);});})(i);}
}setupButtons();

我们发现在回调函数场景中闭包的作用很多是帮我们留下或者说是记住作用域变量,可以让我们的逻辑更加简单。

函数柯里化

wow,好高级的词!

什么是函数柯里化

函数柯里化​​(Currying)是一种将 ​​多参数函数​​ 转换为 ​​一系列单参数函数​​ 的技术。
它的核心思想是:​​每次只接受一个参数,并返回一个新函数,直到所有参数收集完毕,才执行最终计算​​。

总而言之就是:分布传参。

刚才我们在回调函数中了解到:“我们发现在回调函数场景中闭包的作用很多是帮我们留下或者说是记住作用域变量,可以让我们的逻辑更加简单。”

那么:函数柯里化是指将一个多参数函数转换为一系列单参数函数的过程。那么闭包刚好利用它能记住函数定义时的作用域这一特点就可以实现柯里化;

用闭包做函数柯里化

简单例子:

// 普通函数(3个参数)
function sum(a, b, c) {return a + b + c;
}// 手动柯里化(闭包实现)
function curriedSum(a) {return function(b) {return function(c) {return a + b + c;};};
}// 调用方式
console.log(curriedSum(1)(2)(3)); // 6

闭包带来的危害

1. 内存泄漏(Memory Leaks)​

​问题描述​

闭包会长期持有外部函数的变量,阻止垃圾回收(GC),导致内存无法释放。

​示例​

function createHeavyObject() {const bigData = new Array(1000000).fill("X"); // 占用大量内存的变量return function() {console.log(bigData.length); // 闭包引用 bigData,即使外部函数执行完毕};
}const holdClosure = createHeavyObject(); // bigData 无法被回收!

​解决方法​

  • 在不需要闭包时手动解除引用:
    holdClosure = null; // 释放闭包持有的内存
  • 避免在闭包中保存不必要的变量(如 DOM 元素、大对象)。

​2. 性能损耗(Performance Overhead)​

​问题描述​

  • 闭包会创建额外的作用域链,访问外部变量比访问局部变量稍慢。
  • 在频繁调用的函数(如动画、滚动事件)中使用闭包可能导致性能下降。

​示例​

// 每次触发 scroll 都会访问闭包变量
window.addEventListener("scroll", function() {const cached = heavyCompute(); // 闭包可能持有 heavyCompute 的结果console.log(cached);
});

​解决方法​

  • 对于高频操作,尽量使用局部变量而非闭包变量。
  • 用 debounce/throttle 限制触发频率。

​3. 意外的变量共享(Unexpected Shared State)​

​问题描述​

循环中创建的闭包可能共享同一个变量(尤其是用 var 时)。

​示例​

// ❌ 错误写法:所有按钮都输出 3
for (var i = 0; i < 3; i++) {setTimeout(function() {console.log(i); // 输出 3, 3, 3(i 是共享的)}, 100);
}// ✅ 正确写法:用 IIFE 或 let 隔离变量
for (let i = 0; i < 3; i++) {setTimeout(function() {console.log(i); // 输出 0, 1, 2}, 100);
}

​解决方法​

  • 使用 let/const 替代 var(块级作用域)。
  • 用 IIFE(立即执行函数)隔离变量:
    for (var i = 0; i < 3; i++) {(function(j) {setTimeout(function() {console.log(j); // 正确输出 0, 1, 2}, 100);})(i);
    }

​4. 调试困难(Debugging Challenges)​

​问题描述​

闭包的作用域链可能让变量来源难以追踪,增加调试复杂度。

​示例​

function outer() {const secret = 42;return function inner() {debugger; // 在这里查看作用域链,可能有多层闭包console.log(secret);};
}
const mystery = outer();
mystery();

​解决方法​

  • 在 Chrome DevTools 中使用 ​​Scope​​ 面板查看闭包变量。
  • 避免过度嵌套闭包,保持函数简洁。

​5. 闭包与 this 的混淆​

​问题描述​

闭包中的 this 可能丢失预期指向(尤其是嵌套函数中)。

​示例​

const obj = {name: "Alice",greet: function() {return function() {console.log(this.name); // ❌ 输出 undefined(this 指向全局或 undefined)};}
};
obj.greet()(); // 调用内部函数

​解决方法​

  • 使用箭头函数(继承外层 this):
    greet: function() {return () => console.log(this.name); // ✅ 正确输出 "Alice"
    }
  • 提前绑定 this
    greet: function() {const self = this;return function() {console.log(self.name); // ✅ 正确输出 "Alice"};
    }

 

闭包是一把双刃剑,它既可以:创建私有变量,避免全局变量污染 也会:闭包会导致内存泄漏,如果不销毁闭包,他引用的外部变量就会一直保存在内存当中,无法被释放,从而导致内存泄漏 。

就像她对你一样,既能在恋爱中让你开心幸福,也会在吵架时让你痛苦不堪

但是,只要我们珍惜这些幸福,勇敢面对好好处理这些痛苦就能让我们的感情历久弥新。闭包也是一样啊,只要我们利用好它的优点,规避全局变量污染就能让我们变成大佬。

所以,面对再多的困难,再多的误会也要拉紧她的手,会幸福的! 

http://www.dtcms.com/a/438196.html

相关文章:

  • 一元购网站建设教育类网站策划书
  • 2025 AI 落地全景:从技术热潮到产业重构
  • 解析动态数据:如何抓取 JavaScript 加载的 AJAX 内容
  • 聚焦技术落地,展现 AI 重构产业的实践路径。
  • 番禺网站(建设信科网络)小卖部做网站
  • 【氮化镓】P-GaN:提高高温栅极寿命的解决方案
  • 商洛做网站多少钱珠海网站制作哪家便宜
  • 唐山中企动力做网站用php做电子商务网站
  • 05_Pandas数据结构
  • OSPF协议详解3:网络类型、SPF算法、路由选择与特殊区域
  • 10.3总结
  • 算法比赛中的浮点数精度陷阱:从一个货币分解问题说起
  • 昆明手机网站开发不到网站是为什么
  • 反爬虫机制深度解析:从基础防御到高级对抗的完整技术实战
  • 爬坑 10 年!京东店铺全量商品接口实战开发:从分页优化、SKU 关联到数据完整性闭环
  • LeetCode每日一题——判断能否形成等差数列
  • springboot整合sa-token报未能获取有效的上下文处理器
  • 和别人做网站接单赚钱企业网站开发技术期末试题
  • AI-调查研究-93-具身智能 机器人仿真工具大全:从Gazebo到Isaac Sim的全面对比 六大仿真平台
  • 【计算机视觉】霍夫变换检测
  • 【Java核心技术/基础】25道Java核心技术基础面试题及答案
  • AI伦理困局:算法时代的公平与治理之道
  • 网站及app开发招聘榆中县城乡建设局网站
  • MySQL的MHA高可用集群解决方案应用实战(上)
  • 廊坊专业网站网站网站的制作建站人
  • list 实现链表封装节点的底层逻辑:如何克服不连续无法正常访问挑战
  • flash网站模板福州网络推广专员
  • tcpxtract安装教程
  • 1.3 前端框架:加速 LLM 应用开发
  • 从0死磕全栈之Next.js Server Actions 入门实战:在服务端安全执行逻辑,告别 API 路由!