### JavaScript中的闭包详解 #### 一、闭包的基本概念 闭包是JavaScript中一个重要的概念,也是理解和掌握高阶编程技巧的关键。根据司徒正美的介绍,闭包的定义可以概括为:“闭包就是在另一个作用域中保存了一份它从上一级函数或作用域取得的变量(键值对),而这些键值对是不会随上一级函数的执行完成而销毁的。” 这个定义虽然简洁,但对于初学者来说可能并不直观。 从技术层面讲,闭包涉及到两个主要概念:作用域链和变量的作用域。在JavaScript中,每个函数都有自己的作用域链,它决定了函数内部能够访问哪些变量。当一个函数被创建时,它会捕获其外部环境中的变量,并且即使外部函数已经执行完毕,这些变量仍然可以在闭包中被访问。 #### 二、闭包的特点与应用场景 1. **作为函数变量的一个引用**:当函数返回时,闭包保持对其所处作用域中变量的引用,即使这些变量原本应当随着函数执行结束而被销毁。这种特性使得闭包非常适合用于创建私有变量和方法。 2. **一个未释放资源的栈区**:闭包能够保持对外部变量的引用,因此这些变量所占用的内存不会被释放,直到包含闭包的函数完全退出执行环境。 #### 三、闭包的常见实现方式 闭包可以通过多种方式实现,下面列举了几种常见的实现形式: 1. **对象闭包**:通过`with`语句实现。例如: ```javascript var obj = { x: 1 }; with (obj) { console.log(x); // 输出 1 } ``` 这种方式虽然简洁,但由于`with`语句可能导致代码可读性和性能问题,在ES6之后并不推荐使用。 2. **函数闭包**:最常见的闭包形式。例如: ```javascript function outer() { var x = 1; return function inner() { console.log(x); // 输出 1 }; } var closure = outer(); closure(); // 输出 1 ``` 这里`inner`函数构成了一个闭包,它可以访问`outer`函数中的变量`x`。 3. **异常处理闭包**:通过`try...catch`语句实现。例如: ```javascript try { // 异常代码 } catch (e) { // 处理异常 } ``` 在某些情况下,`catch`块也可以看作是一种闭包的形式,尽管这种形式并不常用,且在IE浏览器中可能存在兼容性问题。 #### 四、闭包的实际应用案例 1. **生成唯一ID**: ```javascript var uniqueID = (function () { var id = 0; return function () { return id++; }; })(); console.log(uniqueID()); // 输出 0 console.log(uniqueID()); // 输出 1 ``` 上述代码展示了如何使用闭包来生成全局唯一的ID。每次调用`uniqueID()`时都会返回一个新的递增数值。 2. **实现阶乘计算**: ```javascript var factorial = (function (n) { if (n < 1) { alert("invalid arguments"); return 0; } if (n == 1) { return 1; } else { return n * arguments.callee(n - 1); } })(4); console.log(factorial); // 输出 24 ``` 通过闭包实现递归函数,计算给定数字的阶乘。 3. **封装对象属性的访问器**: ```javascript function User(properties) { var objThis = this; for (var i in properties) { (function () { var t = properties[i]; objThis["get" + i] = function () { return t; }; objThis["set" + i] = function (val) { t = val; }; })(); } } var user = new User({ name: "Bob", age: 44 }); console.log(user.getname()); // 输出 Bob console.log(user.getage()); // 输出 44 user.setname("Mike"); console.log(user.getname()); // 输出 Mike user.setage(22); console.log(user.getage()); // 输出 22 ``` 这个例子展示了如何使用闭包来实现对象属性的getter和setter方法,确保了数据的安全性和封装性。 #### 五、解决实际问题 最后来看一个具体的实例问题:如何使三个`<li>`元素的点击事件能正确弹出各自的索引值? ```html <ul> <li id="a1">aa</li> <li id="a2">aa</li> <li id="a3">aa</li> </ul> <script type="text/javascript"> for (var i = 1; i < 4; i++) { var id = document.getElementById("a" + i); (function (i) { id.onclick = function () { alert(i); // 正确显示 1, 2, 3 }; })(i); } </script> ``` 在这个示例中,通过立即执行函数表达式(IIFE)创建了一个闭包,使得每次循环时都会为每个`<li>`元素绑定一个独立的点击事件处理器。这样,每个处理器都能够访问到对应的`i`值,而不是循环结束后`i`的最终值。这种方法解决了闭包中的经典陷阱,即所有事件处理器都引用同一个变量的问题。 通过以上分析可以看出,闭包是JavaScript语言中一个强大且实用的功能,掌握它可以帮助开发者编写更加灵活和高效的代码。



















- 粉丝: 3
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


最新资源
- 工程项目管理工作存在的问题及优化策略(1).docx
- 大数据在电力设计企业信息化建设的应用探讨.docx
- 多层电梯PLC07级电气自动化(PLC方向)二班.doc
- 互联网+在中职德育主题班会中的实践与研究.docx
- 计算科学导论学科论文的论文-计算机理论论文.docx
- 大型工程网络计划技术的应用复杂性研究.docx
- 《动态网站设计》html试题-答案.doc
- VC程序设计方案复习试题出试卷用.doc
- 客房管理系统-Visual-C++-6.0.doc
- 泵站运行调度中的计算机技术.docx
- 大数据背景下城建档案社会化服务作用体现的策略.docx
- 旅游电子商务的网站.docx
- 汇编语言-汇编语言资源
- 《中国网址》项目管理方案.doc
- 通信传输中光交换技术的关键技术原理和应用.docx
- 电气工程及其自动化的智能化技术微探.docx


