js闭包问题曾经不止一次的困扰过我,在我反复的看了一些资料以后,有以下体会,希望与大家分享:
1、闭包出现的场景
产生闭包至少需要4个元素:外部变量、外层函数、外层函数的局部变量和内层函数,这几个元素的持有关系使得彼此都不会被垃圾回收,从而形成了一个闭环(个人认为这是闭包名字的由来),简单一点说就是外部变量持有内层函数的句柄,内层函数又持有外层函数的变量。看下面函数:
var ou = [];
function ouf(){
for(var i=0;i<3;i++){
var obj = {};
obj.num=function(){
alert(i);
};
ou.push(obj);
}
};
ouf();
ou[0].num();
ou[1].num();
ou[2].num();
这里ou持有内部函数num的句柄,而num中又有外层函数ouf的局部变量i(for中的i 跟放在外面一样),所以只要外部变量ou存在,i 跟ouf就不会被回收。
2、闭包导致的问题
从上面的运行结果来看,ou[0].num();ou[1].num();ou[2].num(); 三个函数的结果都是3,这可能与我们之前期望的0,1,2有所不同,问题出在什么地方呢?我们可以从两个方面理解:
(1)当我们执行ouf()的时候,我们并没有真正的执行num函数,我们仅仅是给obj的num属性传递了一个函数的地址指向,也就是说将来我们要访问obj的num属性的时候,num会根据这一地址去找对应的函数,而在这个函数内部,又存在一个i 的“地址”(由于i是基本类型,说地址不太合适)。只有当我们要执行num的时候,num函数才会去访问i ,而此时的i 的数值已经发生了改变,增加到了3.
(2)我们可以近似的将此处的i 看成num函数的“全局变量”(或者java中的静态变量),所有对i的操作都会影响到将来每个调用num函数的情况。
3、闭包问题的解决
解决闭包问题本质上就是将i这个“全局变量”转化为num的局部变量(这相当于将java中的静态变量转化为实例变量)。对上面的代码做一些修改:
var ou = [];
function ouf(){
for(var i=0;i<3;i++){
var obj = {};
obj.num=(function(s){
return function(){
alert(s);
}
})(i);
ou.push(obj);
}
};
ouf();
ou[0].num();
ou[1].num();
ou[2].num();
(function(s){
return function(){
alert(s);
}
})(i);
这行代码在js中是将i 作为参数传给外面的匿名函数,并立即执行的意思。为什么这样就能解决闭包的问题了呢,我们可以看到,这里的s其实就是外面函数的局部变量,return function(){ alert(s); }仍旧是给obj的num属性指向了一个函数,惟一的区别就是此时这个函数里的变量s变成了局部变量。那么从整体来看,全局变量i 在每一次改变之后,将改变后的不同值分别传给了不同obj对象的num函数的局部变量,这样当我们以后执行num函数的时候,实际上访问的是每个obj自己的num函数对应的自身的变量。当ouf()执行完之后,i 就没有了指向,等待被垃圾回收……
以上“言论”为个人理解,不当之处,欢迎拍砖……
分享到:
相关推荐
JavaScript预编译是一种优化代码执行效率的技术,尤其在大型项目中尤为重要。预编译的主要目的是在实际运行前处理代码,减少解析和运行时的负担,提高应用的性能。本篇文章将深入探讨JavaScript预编译的概念、重要性...
在JavaScript的世界里,深入理解和熟练掌握原生JS是成为优秀前端开发者的关键步骤。"第四课 js进阶课程学习思考-011"着重强调了两个核心概念:JS知识的重要性以及抽象思维模式。以下是对这两个主题的详细阐述: 一...
标题中的“jquery+纯生javascript写的适合初学者”...对于初学者来说,这份资源可以提供实际的编程经验,帮助他们更好地理解和应用JavaScript和jQuery,同时通过五子棋项目的实现,还能锻炼问题解决和逻辑思考能力。
JavaScript,一种广泛应用于Web开发的轻量级编程语言,是前端开发的核心技术之一。这篇文章《JavaScript笔记》的配套代码提供了...记得在学习过程中,不断思考、实践和调试,以加深理解,真正掌握JavaScript的魅力。
JavaScript中的类型转换是处理不同类型数据时需要进行的一种操作,它在编程中扮演着重要的角色。在JavaScript中,存在着多种类型,包括原始类型和对象类型。原始类型主要包括Number、String、Boolean、Undefined和...
全书共9章,分别介绍了JavaScript函数式编程、一等函数与Applicative编程、变量的作用域和闭包、高阶函数、由函数构建函数、递归、纯度和不变性以及更改政策、基于流的编程、类编程。除此之外,附录中还介绍了更多...
JavaScript,简称JS,是一种轻量级的解释型编程语言,广泛应用于网页和网络应用开发,尤其是前端...在实际学习过程中,记得结合实例多动手实践,遇到问题不要怕,多查阅资料,多思考,你会发现JavaScript的魅力无穷。
8. **面试题解析**:可能会包含一些常见的面试问题,如JavaScript的this指向、闭包的应用、跨域解决方案、性能优化策略等。 9. **实践案例**:通过实际的代码示例来巩固理论知识,帮助用户更好地理解和应用所学。 ...
我们先从最简单思考入手.那就会写出下面的代码. for(var i = 0; i < 5; i++) { setTimeout(console.log(i),i*1000); } 这段代码虽然依次打印了,每个i的值0,1,2,3,4.但是,执行的时间却没有起作用.为什么呢
2. **高级特性**:闭包、原型链、作用域、this关键字、函数表达式、箭头函数、模块化(CommonJS、ES6模块)、Promise、异步编程等。 3. **DOM操作**:通过JavaScript与HTML文档对象模型进行交互,包括元素选择、...
2. V8引擎优化:JavaScript Shadow可能借鉴了V8引擎的一些优化技术,如即时编译(JIT)、垃圾回收机制和高性能的数组处理。这些技术有助于提升JavaScript执行效率,使其能够应对高性能计算任务。 3. WebAssembly...
阅读这份笔记,开发者可以深化对JavaScript的理解,提升编程技巧,同时也能了解到作者在学习过程中的思考和经验总结。 总的来说,"js4笔记.rar"和"js3笔记.rar"结合在一起,构成了一套完整的JavaScript学习资源,...
通过这样的学习过程,你不仅可以提升JavaScript技能,还能培养解决问题和独立思考的能力。记住,学习编程最重要的是动手实践,所以不要害怕犯错,每次错误都是向成功迈进的一步。希望这些“js例子”能成为你精通...
5. **闭包**:闭包是JS中的一个重要特性,它可以让内部函数访问外部函数的变量,即使外部函数已经执行完毕。 6. **原型与原型链**:JS中的对象可以通过原型链共享属性和方法,理解原型和__proto__以及如何通过构造...
更多关于闭包的信息可以参考[学习JavaScript闭包](http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html)。 总结来说,本练习涉及了JavaScript中多个重要的基础概念,包括作用域、异步处理、...
JavaScript,通常简称为JS,是Web开发中的核心技术,主要用于网页和应用程序的交互性。它是一种轻量级的解释型编程语言,具有动态类型、原型继承和函数作为一等公民等特性。 在这一系列的源代码教程中,你将探索...
这是Google开发的一个高性能的JavaScript和WebAssembly虚拟机,被广泛应用于Chrome浏览器和Node.js环境中。V8引擎通过即时编译(JIT)将JavaScript源码转换为机器码,实现了高效的运行速度。理解V8的内存管理,如...
总之,JavaScript函数式编程提供了一种新的思考问题和解决问题的方式,它鼓励我们编写无副作用、可组合的代码,提高代码质量,降低维护难度。掌握函数式编程的思想和技术,对于提升JavaScript编程能力大有裨益。在...