不同语言闭包的捕获方式
总览
- C++ 根据在捕获列表中标注的方式进行捕获。
- Java 按照值捕获(而且 Java 在某些情况下还要求显式的 final 修饰符)。
- JavaScript:见
JavaScript 捕获。
- 注意:捕获和传值是不同的!例如:JavaScript 在函数参数传递时仍然时按照值传递。
- Python/Go 按照引用捕获,for 循环不会创造新的作用域。
JavaScript 捕获
看上去是引用捕获,但是 for 循环的 let 和 const 绑定会创造新的作用域。
function generateSquaringFunctions() {
const funcList = [];
const values = [1, 2, 3];
for (var i of values) {
// ^^^
// var: [9, 9, 9]
// let/const: [1, 4, 9]
const square = function () {
return i * i;
};
funcList.push(square);
}
return funcList;
}
const [square1, square2, square3] = generateSquaringFunctions();
console.log(square1(), square2(), square3());
可以参考 Javascript’s Hoisting(变量提升、函数提升、类提升)。
其他测试:
(() => {
let download = async () => console.log(1);
(() => {
if (true) {
download = async () => console.log(2);
}
})();
(async () => {
await download();
})();
})();
// 2
唯独在 TamperMonkey 上看上去不是引用绑定,不知道为什么。测试发现在复杂判断条件下的赋值不 work。最后感觉可能是 TamperMonkey 在 CROS 脚本中运行的那套环境和主页面的运行环境不一样。