在 ColdFusion 中,我可以按值捕获封闭变量吗?

In ColdFusion can I capture closed-over variables by value?

假设我们正在构建一个闭包列表,这些闭包对值 i 执行某些功能,其中 i 是每次迭代的新值。例如:

function foo() {
    var result = [];
    for (var i = 0; i < 4; i++) {
        arrayAppend(result, function() { return i; });
    }
    return result;
}

flist = foo();
newline = "<br>";
for (f in flist) {
    WriteOutput(f() & newline);
}

似乎 CF 正在通过引用捕获 i——上面的结果是:

4
4
4
4

这些结果在 CF2011、CF2016、Lucee4.5 和 Lucee5 中是相同的(我通过 trycf.com 进行了测试,方便,假设它确实是 运行 那些引擎)。

我已经实施了一种我称之为 value_capturing_closure 的迂回方式,但我真的不想把它强加给我的团队,因为最好坚持使用每个人都熟悉的 CF 习语和。是否可以在 CF 中使用原生 CF 闭包语法按值捕获变量?

这就是闭包的工作原理。您需要做的是创建一个值的副本,并将该副本绑定到一个未持久化的函数。这可以通过创建一个接受参数的函数然后创建一个函数来实现。

function foo() {
    var result = [];
    for (var i = 0; i < 4; i++) {
        arrayAppend(result, function(x) {   
            return function(){ return x };
        }(i));
    }
    return result;
}

或为了清楚起见分开成一个单独的函数

function foo() {
    var result = [];
    for (var i = 0; i < 4; i++) {
        arrayAppend(result, createClosure(i));
    }
    return result;
}


function createClosure(x) {
    return function() {
        return x;
    }
}

正如 Dan Robert 在上面所说的那样,关键是通过在创建函数时传入函数来捕获创建函数时的迭代。

所以你的代码在 Lucee 上可以这样写:

function foo() {
    var f = (n) => () => n;
    var result = [];
    for (var i = 0; i < 4; i++) {
        arrayAppend(result, f(i));
    }
    return result;
}

flist = foo();
newline = "<br>";
for (f in flist) {
    WriteOutput(f() & newline);
}

https://www.trycf.com/gist/c1f521fa190e6d32aa07de93d13580d8/lucee5?theme=monokai

A​​CF 2018 update 5 应该也支持粗箭头语法,但我现在无法测试。