我的翻译小站: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. UGUI双击事件

    经测试在Android.ios平台下无效 using UnityEngine; using UnityEngine.EventSystems; using System.Collections; us ...

  2. one by one 项目 part 2

    在网上百度了一下mySQL常用语句 ,整理如下: 1.说明:创建数据库 CREATE DATABASE database-name 2.说明:删除数据库 drop database dbname 3. ...

  3. Python基础语法题库

    引言: 语法练习包括Python基础语法.数据类型.字符编码和简单文件操作等内容. 正文(参考答案附录在题目下方): 1.Python 里用来告知解释器跳过当前循环中的剩余语句,然后继续进行下一轮循环 ...

  4. python集合的交,差,并,补集合运算汇总

    集合操作实际用的不多,了解即可. 交集:          ( & 或者 intersection ) 并集:    ( | 或者 union ) 差集:   ( -  或者  differe ...

  5. ingress 密码验证

    traefik ingress 上面的方式需要引入haprox或者nginx,多引入了一个代理转发层,其实ingress本身就提供了basic auth的支持,在ingress规则中添加额外的认证an ...

  6. 消息 14607,级别 16,状态 1,过程 sp_send_dbmail,第 141 行 profile 名称无效

    错误:消息 14607,级别 16,状态 1,过程 sp_send_dbmail,第 141 行profile 名称无效 原因: 用SA帐户是可以发送邮件的,但换了另外一个帐户后却提示以上错误. 解决 ...

  7. oracle改变表中列的编码

    ALTER TABLE table_name CHANGE `name` `name` VARCHAR(255) CHARACTER SET utf8;

  8. Spring简单获得实体类的实例, 使用ApplicationContext()方法的几点注意事项

    今天接触了Spring的初步用法, 感觉跟实例化实体类没啥区别, 像这种简单的代码还不如直接实例化来的方便, 这样使用Spring的话总共需要三个文件 第一个当然是一个实体类了, 定义好属性, get ...

  9. hdoj1014 互质

    Uniform Generator Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  10. LuoguP1226 【模板】快速幂||取余运算

    题目链接:https://www.luogu.org/problemnew/show/P1226 第一次学快速幂,将别人对快速幂原理的解释简要概括一下: 计算a^b时,直接乘的话计算次数为b,而快速幂 ...