我的翻译小站:https://www.zcfy.cc/article/javascript-loops-and-scope

翻译原文链接:https://flaviocopes.com/javascript-loops-and-scope/

JavaScript有一个特点,也许会让开发者头痛, 是与循环和作用域相关的.

举个例子:

const operations = []

for (var i = 0; i < 5; i++) {
operations.push(() => {
console.log(i)
})
} for (const operation of operations) {
operation()
}

它基本是循环了5次,将一个函数添加到operations数组里面。这个函数可打印出循环变量索引值i.

运行这些函数后

期望的结果应该是:

0
1
2
3
4

但实际发生的是这样的:

5
5
5
5
5

为什么会有这种情况? 因为使用的是var.

由于提升了var变量, 上面的代码等同于

var i;
const operations = [] for (i = 0; i < 5; i++) {
operations.push(() => {
console.log(i)
})
} for (const operation of operations) {
operation()
}

因此,在for-of循环中, i 依然是可见的, 它等于5,并且每次在函数中涉及到i ,都将使用这个值。

那么我们应该如何做让其变成我们想的这样呢?

最简单的方案是用 let 声明. 在ES2015中介绍到, 它们有很大的帮助,能避免关于使用var声明的一些奇怪问题。

简单的在循环变量时将var 变成 let ,能够很好的运行:

const operations = []

for (let i = 0; i < 5; i++) {
operations.push(() => {
console.log(i)
})
} for (const operation of operations) {
operation()
}

这是输出结果:

0
1
2
3
4

这是怎么实现的呢?这是因为每次循环重复的时候,都将重新创造i ,同时每个函数添加operations数组时,能获取它本身的i

记住你不能使用 const在这种情况下, 因为这会导致for在第二次循环时, 尝试赋新值报错。

另外一个非常普遍的解决这个问题是使用pre-ES6代码, 同时它被称作即时调用函数表达式 (IIFE).

在这种情况下,你可以包装整个函数,并将i 绑定在它上面。自这种方式,你正在创造一个能立即执行的函数,你从其返回的一个新的函数。因此我们可以稍后执行它。

const operations = []

for (var i = 0; i < 5; i++) {
operations.push(((j) => {
return () => console.log(j)
})(i))
} for (const operation of operations) {
operation()
}

【翻译】JavaScript循环和作用域的更多相关文章

  1. 【翻译】JavaScript中的作用域和声明提前

    原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译开始=== 你知道下面的JavaScript脚本执 ...

  2. javascript(面向对象,作用域,闭包,设计模式等)

    javascript(面向对象,作用域,闭包,设计模式等) 1. 常用js类定义的方法有哪些? 参考答案:主要有构造函数原型和对象创建两种方法.原型法是通用老方法,对象创建是ES5推荐使用的方法.目前 ...

  3. 认识javascript中的作用域和上下文

    javascript中的作用域(scope)和上下文(context)是这门语言的独到之处,这部分归功于他们带来的灵活性.每个函数有不同的变量上下文和作用域.这些概念是javascript中一些强大的 ...

  4. Javascript之变量作用域

    分析: 无论是强类型语言c#.c++.java等语言,还是弱类型语言如Javascript,所有变量可以抽象为两种类型,即局部变量和全局变量. 全局变量:整个作用域可见. 局部变量:局部可见,退出作用 ...

  5. 深入理解 JavaScript 变量的作用域和作用域链

    一个变量的作用域(scope)是程序源代码中定义这个变量的区域.简单的说,作用域就是变量与函数的可访问范围.全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义.局部变量是在函数体内 ...

  6. javascript篇-----函数作用域,函数作用域链和声明提前

    在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于 ...

  7. JavaScript之函数作用域

    有过类似C语言编程经验的同学应该都知道“块级作用域(block scope)”:花括号内的每一段代码都具有各自的作用域,而且在声明它们的代码段之外是不可见的.而在JavaScript中是没有块级作用域 ...

  8. JavaScript中的作用域和声明提前

    [翻译]JavaScript中的作用域和声明提前 原文:http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html ===翻译 ...

  9. JavaScript函数变量作用域

    变量作用域 在JavaScript中,用var申明的变量实际上是有作用域的. 如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量. 如果两个不同的函数各自申明了同一变 ...

随机推荐

  1. sql server 2000能否得到一个表的最后更新日期?

    如果是SQL 2005 或 2008.运行下面的代码.就可以看到从上次启动SQL 服务以来,某个表的使用情况,包括select/update/delete/insert. SELECT * FROM ...

  2. JS 实现Json查询的方法实例

    其实很简单,我这部分代码,前一部分是简单的实现如何使用JS写模板,第二个就是具体的实现了JSON查询的一个扩展. 以后查询Json就有了利器了. 代码如下: /*         * 定义模板函数   ...

  3. redmine邮件配置

    网上找了半天,有很多答案,最后自己测试找出一个解决办法. 1.找到安装位置 D:\Bitnami\redmine-2.5.2-2\apps\redmine\htdocs\config下的文件confi ...

  4. C#实现支持单点登录的一个存储用户信息的类

    网上有很多介绍单点登录的文章,但多为架构设计以及概念性文章,而本文将介绍单点登录的具体具体实现 利用哈希表,作为保存登录用户的队列        private static Hashtable m_ ...

  5. 电脑连接树莓派Pi Zero W

    作者:陈拓 chentuo@ms.xab.ac.cn 2018.05.16/2018.06.09 0.  概述 本位介绍两种电脑连接树莓派Pi Zero W的方法: 电脑通过USB以太网连接树莓派Ze ...

  6. spring ioc 注解配置

    要注意spring 版本与jdk的兼容性 applicationContext-resource.xml: <beans xmlns="http://www.springframewo ...

  7. oracle与DB2

    1.体系结构,DB2的实例和数据库分开的做法,我个人还是比较喜欢的,因为实例可以创建多个,数据库的恢复直接恢复到实例下就可以了,相对ORACLE简单多了. 2.管理工具,DB2的管理工具做得太简陋了, ...

  8. linux替换字符串的几种方法

    1. 基本替换:s/str1/str2/ 替换当前行第一个str1为str2:s/str1/str2/g 替换当前行所有str1为str2:n,$s/str1/str2/ 替换第 n 行开始到最后一行 ...

  9. twitter 等网站console.log不能使用,可用alert或者

    function setConsole() { var iframe = document.createElement('iframe'); iframe.style.display = 'none' ...

  10. FP真验货客户的成品和半成品编码部分没有带尾续,导致FP规划错误 IN_SALES_ORDER数据不带CZ

    错误描述:真验货客户的成品和半成品编码部分没有带尾续,导致FP规划错误 IT角度: IN_SALES_ORDER数据不带CZ 现时前台页面数据: 现时后台数据: 一.跟进情况 1.执行SAP_SALE ...