JavaScript含setTimeout的test函数输出差异是否由闭包导致?
问题代码
function test(str) { setTimeout(() => { console.log(str); }, 10000); } let i = "1"; test(i); //test 1 console.log(i, "sync"); i = "2"; test(i); //test 2 console.log(i, "sync");
问题1:test 1、test 2依次打印1和2是不是闭包导致的?
不是,核心原因是JS基本类型的值传递特性:
- 字符串属于JS基本数据类型,调用
test(i)时,会把当前i的值完整拷贝一份赋值给test的形参str。两次调用test会生成两个独立的函数执行上下文,各自上下文里的str分别存储"1"和"2",互不干扰。 setTimeout的箭头函数确实形成了闭包,作用是让异步回调可以访问到当前test上下文里的str变量,但闭包不是输出差异的核心原因,核心是传参时已经做了值拷贝。
问题2:两种输出差异的原因
你描述的「去掉setTimeout直接打印str得到i最后取值」的场景,和原代码的差异本质是是否做了值拷贝、以及是否是异步执行:
首先要纠正一个误区:如果仅删除原代码里的setTimeout,直接打印形参str,运行结果是依次输出1、1 sync、2、2 sync,不会出现只输出i最后取值的情况。
你说的输出最后取值的场景,应该是test不接收参数,直接引用外部变量i的写法:
// 会输出两次2的写法 function test() { setTimeout(() => { console.log(i); // 直接引用外部的i,没有传参拷贝步骤 }, 10000); }
这种场景和原代码的差异原因:
- 原代码传参时做了值拷贝,每个回调捕获的是各自上下文里独立的
str,不管同步还是异步执行,拿到的都是调用时拷贝的值 - 直接引用外部
i的写法,所有回调捕获的是同一个作用域下的同一个i变量,异步回调执行时i已经被重新赋值为2,所以都会打印最后取值
内容的提问来源于stack exchange,提问作者Ali Özgenç
相关产品推荐
相关产品推荐

