闭包(一)

闭包的概念十分的抽象,直接上干货吧

function A(){
  var num=0;
  function B(){
	console.log(++num);
  }
  return B;
}
var C=A();
C();//1
C();//2
C();//3
在这段代码中,B是在函数A内部声明的函数,但是因为A中将B给return了出去,所以在A外部声明的var C=A(),相当于将C指向了函数B,这就形成了闭包。简单的说,就是内部的函数被外部的变量引用,这就是闭包。

因为内部函数B在外部被引用,所以A内部的变量num不会被释放(涉及到JavaScript的内存回收机制),A的内部就形成了一个相对独立的环境。多次C()的执行,相当于在A的这个环境内,多次执行了B方法。所以,num的值因为每次都执行了++num而变化。

再来稍微深入一点点

function A(){
  var num=0;
  function B(){
	console.log(++num);
  }
  return B;
}
var C=A();
C();//1
C();//2
C();//3
var D=A();
D();//1
D();//2
C();//4
可以看到在执行方法D的时候,num的值又是重新从0开始,但是再执行第四次C的时候,输出的却是4,这说明了什么?

说明了两次闭包的形成各自被赋予了一块独立的内存,两块内存之前互不干扰。

### 闭包的基本概念 闭包是指函数能够访问并记住其词法作用域,即使该函数在其作用域外执行。闭包的形成通常是因为函数内部定义了另函数,并且内部函数引用了外部函数的变量。这种特性使得闭包可以访问外部函数的参数和局部变量,即使外部函数已经执行完毕。 ### 闭包的应用场景 闭包JavaScript 中有着广泛的应用,包括但不限于以下几种情况: - **数据隐藏和封装**:通过闭包可以创建私有变量和方法,防止外部直接访问和修改数据。 - **回调函数**:闭包常用于异步编程中的回调函数,确保回调函数能够访问到正确的上下文。 - **函数柯里化**:通过闭包可以实现函数的部分应用,即将函数的部分参数固定,返回个新的函数。 - **记忆化**:闭包可以用来缓存计算结果,避免重复计算。 - **模块模式**:闭包可以用来实现模块模式,将相关的功能和数据封装在个模块中。 - **延迟执行**:闭包可以用于延迟执行某些操作,直到需要时才执行。 ### 闭包的示例代码 #### 封装变量 以下示例展示了如何使用闭包来封装变量,实现计数器功能: ```javascript function createCounter() { let count = 0; return function() { return ++count; }; } const counter = createCounter(); console.log(counter()); // 输出:1 console.log(counter()); // 输出:2 ``` 在这个例子中,`createCounter` 函数返回了个内部函数,该内部函数能够访问 `createCounter` 函数中的局部变量 `count`。即使 `createCounter` 函数已经执行完毕,返回的内部函数仍然可以访问和修改 `count` 变量 [^2]。 #### 实现私有变量和私有方法 以下示例展示了如何使用闭包来实现私有变量和私有方法: ```javascript function createPerson() { let name = "John"; function changeName(newName) { name = newName; } function getName() { return name; } return { changeName, getName }; } const person = createPerson(); console.log(person.getName()); // 输出:John person.changeName("Alice"); console.log(person.getName()); // 输出:Alice console.log(person.name); // 输出:undefined ``` 在这个例子中,`createPerson` 函数返回了个对象,该对象包含两个方法 `changeName` 和 `getName`。这两个方法都能够访问 `createPerson` 函数中的局部变量 `name`,但外部无法直接访问 `name` 变量 [^2]。 #### 利用闭包处理事件 以下示例展示了如何使用闭包来处理按钮点击事件: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>闭包Demo</title> </head> <body> <button>测试1</button> <button>测试2</button> <button>测试3</button> <script type="text/javascript"> var btns = document.getElementsByTagName('button'); for (var i = 0, length = btns.length; i < length; i++) { (function(j) { var btn = btns[j]; btn.onclick = function() { alert('第' + (j + 1) + '个'); }; })(i); } </script> </body> </html> ``` 在这个例子中,通过立即执行函数 `(function(j) { ... })(i)` 创建了闭包,使得每个按钮的 `onclick` 事件处理函数能够访问到正确的索引值 `j` [^3]。 #### 闭包带有记忆属性 以下示例展示了闭包的记忆属性,即使函数执行完毕后,仍然可以访问函数作用域内的变量: ```javascript function op(x) { function op2(y) { x *= y; return x; } return op2; } var fun = op(2); var re = fun(-9); console.log(re); // 输出:-18 ``` 在这个例子中,`op` 函数返回了 `op2` 函数,`op2` 函数能够访问 `op` 函数中的局部变量 `x`,即使 `op` 函数已经执行完毕 [^5]。 ### 相关问题 1. 闭包JavaScript 中有哪些应用场景? 2. 如何使用闭包实现私有变量和私有方法? 3. 闭包如何帮助实现函数柯里化? 4. 闭包的记忆属性是如何工作的? 5. 如何使用闭包处理事件?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值