我的翻译小站: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. Python线程优先级队列(Queue)

    Python的Queue模块中提供了同步的.线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列 LifoQueue,和优先级队列PriorityQueue.这些队列都实 ...

  2. python Count类(转)

    1.collections模块 collections模块自Python 2.4版本开始被引入,包含了dict.set.list.tuple以外的一些特殊的容器类型,分别是: OrderedDict类 ...

  3. 最短路径-Dijkstra算法(转载)

    注意:以下代码 只是描述思路,没有测试过!! Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始 ...

  4. ldd3 源码相关问题参见

    参考地址: http://www.verydemo.com/demo_c92_i235635.html http://blog.csdn.net/silvervi/article/details/64 ...

  5. sdc docker连接

    curl -O https://raw.githubusercontent.com/joyent/sdc-docker/master/tools/sdc-docker-setup.sh &&a ...

  6. jquery 不选择第一个

    参考 https://zhidao.baidu.com/question/174343639.html th:not(':first')

  7. Python staticmethod() 函数

    Python staticmethod() 函数  Python 内置函数 python staticmethod 返回函数的静态方法. 该方法不强制要求传递参数,如下声明一个静态方法: class ...

  8. 安装使用phpStudy在本机配置php运行环境

    前言: php开发的初学者,强烈推荐使用phpStudy集成环境,一方面这个的确很好用(本人电脑安装了jspStudy,可以同时调试php和jsp),另一方面呢,虽然本人是技术控,但对这些繁杂的安装部 ...

  9. TZOJ 2755 国际象棋(广搜+哈希)

    描述 在n*n的国际象棋棋盘中,给定一“马(Knight)”和一“后(Queen)”的位置,问“马”能否在m步之内(包括m步)到达“后”的位置?马的走法是:每步棋先横走或直走一格,然后再斜走一格,即走 ...

  10. 测试SQL

    create database testDB create table users(    id int primary key identity(1,1),    uname nvarchar(20 ...