不同语言闭包的捕获方式

总览

  • 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 脚本中运行的那套环境和主页面的运行环境不一样。