JavaScript---循环与闭包
循环与闭包
先看一个demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
for(var i = 0; i <= 5; i++){ setTimeout(function timer(){
console.log(i);
}, i*1000); } </script>
</body>
</html>
结果会打印出什么? 相信大家都知道 答案是 6个6; 我们本意是打印出:0,1,2,3,4,5 但结果却是6个6, 为什么?首先解释一下为什么打印出6:这里涉及到延时函数的执行机制,虽然延时函数表明是i秒后执行,而i秒是相对与所有可执行代码执行完那一刻开始计时的,也就是等for循环结束之后,延时函数才开始执行。但此时 i= 6;所以会打印出6. 现在在解释一下为什么是6个6:很简单,for循环每执行一次就创建出一个延时函数,执行了6次,就会有6个延时函数。这6个延时函数共享一个作用域(本例中全局作用域) i又累加到6,所以会打印出6个6!!
分析完整个过程,你知道问题出现在哪里吗? 有2个问题 1:每执行一次for循环,应该执行一次延时函数,但并没有。2:所有的延时函数共享一个作用域。
知道问题的地方,那就很好解决了:每循环一次,创建一个作用域 。 关键是如何实现“每循环一次,创建一个作用域”, 其实很简单,每循环一次,就立即执行一次延时函数,立即执行函数(IIFE)就派上用场了 它的原理很“粗暴”:每个延时函数都会将IIFE在每次迭代中创建的作用域 封闭起来。ok,修改一下我们的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
for(var i = 0; i <= 5; i++){
(function(){
setTimeout(function timer(){
console.log(i);
}, i*1000);
})(); } </script>
</body>
</html>
在chrome中显示:

咦??? 怎么还是6个6!!! 问题出在哪里? 其实很简单,仔细看一下,我们的IIFE只是一个什么都没有的空作用域(i是全局变量,处于全局作用域中) 它需要有自己的变量,用来在每个迭代中存储i的值 再来改进一下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
for(var i = 0; i <= 5; i++){
(function(){
var j = i;
setTimeout(function timer(){
console.log(j);
}, j*1000);
})(); } </script>
</body>
</html>
在chrome中显示:

把i值存进来,就可以实现 我们的预期了。到现在为止,代码已经是没有错误的了。但是,还可以优化:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
for(var i = 0; i <= 5; i++){
(function(i){
setTimeout(function timer(){
console.log(i);
}, i*1000); })(i)
} </script>
</body>
</html>
把i当作参数传进去,我们的代码就更完美了。
2017-3-23 0:19
JavaScript---循环与闭包的更多相关文章
- JavaScript葵花宝典之闭包
闭包,写过JS脚本的人对这个词一定不陌生,都说闭包是JS中最奇幻的一个知识点, 虽然在工作中,项目里经常都会用到~ 但是是不是你已经真正的对它足够的了解~~ 又或者是你代码中出现的闭包,并不是你刻 ...
- 让你分分钟学会Javascript中的闭包
Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...
- 深入理解javascript原型和闭包(4)——隐式原型
注意:本文不是javascript基础教程,如果你没有接触过原型的基本知识,应该先去了解一下,推荐看<javascript高级程序设计(第三版)>第6章:面向对象的程序设计. 上节已经提到 ...
- javascript中的闭包、模块与模块加载
一.前言 闭包是基于词法作用域( 和动态作用域对应,词法作用域是由你写代码时,将变量写在哪里来决定的,因此当词法分析器处理代码时,会保持作用)书写代码时所产生的自然结果,甚至不需要为了利用闭包而有意 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- javascript中的闭包解析
学习javaScript已经有一段时间了,在这段时间里,已经感受到了JavaScript的种种魅力,这是一门神奇的语言,同时也是一门正在逐步完善的语言,相信在大家的逐步修改中,这门语言会逐步的完善下去 ...
- 《深入理解javascript原型和闭包系列》 知识点整理(转)
深入理解javascript原型和闭包系列 对原型和闭包等相关知识的讲解,由浅入深,通俗易懂,每个字都值得细细研究. 一.一切都是对象 1. typeof操作符输出6种类型:string boolea ...
- 《深入理解javascript原型和闭包系列》 知识点整理
深入理解javascript原型和闭包系列 对原型和闭包等相关知识的讲解,由浅入深,通俗易懂,每个字都值得细细研究. 一.一切都是对象 1. typeof操作符输出6种类型:string boolea ...
- JavaScript中的闭包理解
原创文章,转载请注明:JavaScript中的闭包理解 By Lucio.Yang 1.JavaScript闭包 在小学期开发项目的时候,用node.js开发了服务器,过程中遇到了node.js的第 ...
- javascript作用域和闭包之我见
javascript作用域和闭包之我见 看了<你不知道的JavaScript(上卷)>的第一部分--作用域和闭包,感受颇深,遂写一篇读书笔记加深印象.路过的大牛欢迎指点,对这方面不懂的同学 ...
随机推荐
- 使用LocationManager来获取移动设备所在的地理位置信息
在Android应用程序中,可以使用LocationManager来获取移动设备所在的地理位置信息.看如下实例:新建android应用程序TestLocation. 1.activity_main.x ...
- 一步一步学EF系列三【数据迁移】
我们每篇的内容都不多,所以希望在学习的过程中最后能亲自敲一下代码 这样更有利于掌握. 我们现在接着上篇的例子,我们现在给随便的表增加一个字段 CreateTime 创建日期 运行一下 看看会怎么样 修 ...
- PKU 1521 Entropy(简单哈弗曼树_水过)
题目大意:原题链接 给你一个字符串,首先是计算出一个按正常编码的编码长度,其次是计算出一个用霍夫曼编码的编码长度,最后求正常编码的长度除以霍夫曼编码长度的比值,保留一位小数. 解题思路:需要知道 1. ...
- 使用Xib创建自定义视图(不是cell)时需要注意的问题
开发项目过程中,有些地方不免会用到Xib来提高开发效率,如果你的手速够快,写代码建视图,我并不反对这样做.因为我以前也是纯手写代码开发. 进入正题,Xib好用,但是这些下面这些问题需要注意一下. 问题 ...
- oracle安装完成后目录中不论有没有tnsnames.ora和listener.ora文件 PLSQL都能连上的问题解决方法
今天遇到这个问题了,发现listener.ora文件和tnsnames.ora文件在Net Work文件夹下没有,正常情况下安装完oracle或者是oracle Client是会有的,但是在Net M ...
- Linux上db2安装
Linux上db2安装:https://blog.csdn.net/nayanminxing/article/details/69372283
- 【c++ primer, 5e】构造函数 & 拷贝、赋值和析构
[构造函数] 1.构造器就是创建对象时被调用的代码. 2.如果没有自定义构造器,那么编译器将自动合成一个默认的无参构造器. 3.自定义的构造器不允许加const,所创建const的对象只有在构造器代码 ...
- LeetCode (65):Same tree
Total Accepted: 83663 Total Submissions: 200541 Difficulty: Easy Given two binary trees, write a fun ...
- C++之STL迭代器(iterator)
[摘要]本文是对STL--迭代器(iterator)的讲解,对学习C++编程技术有所帮助,与大家分享. 原文:http://www.cnblogs.com/qunews/p/3761405.html ...
- bat(续六)-windows批处理set命令
windows批处理set命令 [设置变量]格式:set 变量名=变量值详细:被设定的变量以%变量名%引用 [取消变量]格式:set 变量名=详细:取消后的变量若被引用%变量名%将为空 [展示变量]格 ...