for循环闭包的应用

for循环闭包的应用

var a=[],b=[],c=[],d=[]
for(var i=0;i<10;i++){
    a[i]=function(){// 上级作用域是全局作用域,i是全局作用域中的i,循环结束不形成私有作用域
        console.log(i)
    };
    b[i]=(function(){ // 上级作用域是私有作用域,i是全局作用域中的i。循环结束形成多个私有作用域
        return function(){console.log(i)}
    })();
    c[i]=(function(c_i){ // 上级作用域是私有作用域中,i是私有作用域中的i。循环结束形成多个私有作用域
        // 用形参保留全局作用域当次循环中的i的值
        return function(){console.log(c_i)}
    })(i);
}
for(let i=0;i<10;i++){ // 上级作用域块儿级作用域,i是块儿级作用域中的i。循环结束形成多个块儿级作用域
    d[i]=function(){
        console.log(i)
    };
}
console.log(a[1](),b[1](),c[1](),d[1]()) // 10 10 1 1
  1. 语句执行时,赋值运算符的右侧是一个值,字符串类型的值(函数字符串)
  2. 函数执行的时候,变量i从本级作用域查找,如果本级没有定义,则到上级作用域查找,如果找到,便不在向上查找,该值即为变量i的值(如果变量i只定义了没赋值,值为undefined),如果没有找到接着向上查找,直到全局作用域,没有则为undefined
  3. 数组a和b的情况相同点是,i是全局作用域中的i,由于此时循环结束,i的值是10 ,所以输出的是10
  4. 数组a和b的情况不同点是,a的上级作用域是全局作用域,b的上级作用域是私有作用域
  5. 上级作用域就是函数定义时候的作用域,与在哪里执行没有关系
  6. 匿名自执行函数通过传参的方式得到本次循环的i的值
  7. 由于函数return一个引用类型的数据被外部变量(数组成员)接收,因而不被销毁,for循环的每次都形成一个不销毁的私有作用域,循环结束后这些私有作用域都存在,除非手动销毁或者关闭页面
  8. 块儿级作用域和函数私有作用域具有同等特性
### 闭包的实际应用场景 #### 1. 数据封装与隐私保护 闭包允许开发者在函数内部定义私有变量,从而实现数据的封装。这种特性使得外部无法直接访问某些敏感的数据或逻辑,仅可以通过特定的方法来操作它们。 ```javascript function createCounter() { let count = 0; // 私有变量 return { increment: function () { count++; }, // 修改计数器 get: function () { return count; } // 获取当前值 }; } const counter = createCounter(); counter.increment(); // 调用方法修改count console.log(counter.get()); // 输出1 [^1] ``` 此代码展示了如何利用闭包隐藏`count`变量,并提供受控接口对其进行增减操作。 #### 2. 函数工厂模式 通过返回不同的函数,可以根据传入参数动态生成具有不同行为的新函数。这种方式常用于配置初始化或者构建一系列相似功能但略有差异的操作工具集。 ```javascript function multiplier(factor) { return function (value) { return value * factor; }; } let doubleIt = multiplier(2); console.log(doubleIt(5)); // 结果为10 [^3] ``` 在此例子中,`multiplier`作为高阶函数接受一个乘法因子factor, 并返回一个新的匿名函数完成具体的数值计算工作. #### 3. 延迟求值与事件处理程序绑定 当需要延迟执行某段代码直到某个条件满足时(比如点击按钮触发动作),可以借助闭包保存状态直至适当时候再调用关联的功能模块。 ```javascript for(var i=0;i<5;i++) { setTimeout(function(){ console.log(i); },i*1000); } // 上述代码会打印五次'5', 若要得到期望的结果即依次递增,则需调整如下: for(let j=0;j<5;j++) { setTimeout(() => { console.log(j); },j*1000); } // 或者使用立即执行函数表达式(IIFE) for(var k=0;k<5;k++) { (function(k){ setTimeout(function(){console.log(k)},k*1000); })(k); } ``` 以上片段解释了为什么原始版本会出现问题以及修正后的解决方案之一是如何运用IIFE保持每次循环迭代独立性的良好做法.[^4] #### 4. 高效缓存机制设计 为了提升性能表现,在面对重复运算请求的时候,我们可以采用记忆化技术存储已知答案以便后续快速检索而无需重新计算整个过程。 ```javascript var fibonacciMemoizer = (()=>{ const memo={}; var fib=(num)=>{ if(memo[num]!=undefined)return memo[num]; if(num<=1)memo[num]=num; else{ memo[num]=(fib(num-1)+fib(num-2)); } return memo[num]; }; return fib; })(); console.log(fibonacciMemoizer(7));//输出结果应为13 [^1] ``` 该示例演示了一个简单的斐波那契序列计算器,其中引入了备忘录对象memo储存已经解决过的子问题解,避免不必要的冗余劳动。 --- ### Python中的闭包应用案例 虽然本文主要围绕JavaScript展开讨论,但在Python里同样存在丰富的关于闭包应用场景。例如下面展示了一种常见的误解情况下的修复办法: ```python def generate_functions(): functions_list = [] for i in range(3): def func(x=i): # 这里的默认参数x绑定了当时的i值而不是最终结束时的状态. print(x) functions_list.append(func) return functions_list funcs = generate_functions() for f in funcs: f() # 正确输出应该是分别显示数字0至2而非三个相同的最后更新值2。 ``` 上述脚本纠正了之前提到的那个常见陷阱——由于缺乏对闭包特性的正确认识而导致的行为异常现象。[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值