以下是一个语法正确的JavaScript程序——只是,它的行为并不完全符合我们的预期。问题的标题应该帮助你的眼睛聚焦到问题区域。
如果我使用唯一标识符,程序就可以完美地运行。
const recur = (...args) =>
({ type: recur, args })
const loop = f =>
{
let acc = f ()
while (acc.type === recur)
acc = f (...acc.args)
return acc
}
const repeat = n => f => x =>
loop ((n = n, f = f, x = x) => // The Problem Area
n === 0
? x
: recur (n - 1, f, f (x)))
console.time ('loop/recur')
console.log (repeat (1e6) (x => x + 1) (0))
console.timeEnd ('loop/recur')
// Error: Uncaught ReferenceError: n is not defined
const recur = (...args) =>
({ type: recur, args })
const loop = f =>
{
let acc = f ()
while (acc.type === recur)
acc = f (...acc.args)
return acc
}
const repeat = $n => $f => $x =>
loop ((n = $n, f = $f, x = $x) =>
n === 0
? x
: recur (n - 1, f, f (x)))
console.time ('loop/recur')
console.log (repeat (1e6) (x => x + 1) (0)) // 1000000
console.timeEnd ('loop/recur') // 24 ms
只有这样没有意义。现在让我们谈谈原始代码,它不使用$
前缀。
当评估loop
的lambda时,由repeat
接收的n
在lambda的环境中可用。将内部的n
设置为外部n
的值应该有效地shadow外部的n
。但是,JavaScript将其视为某种问题,导致内部的n
结果被赋值为undefined
。
对我来说,这似乎是一个错误,但我很擅长阅读规范,所以我不确定。
这是一个错误吗?
let
和const
一样。例如,const v = v
不起作用,因为新变量已经遮蔽了外部作用域中的v
。 - Sylwestern = n
将给出var n = arguments.length > 0 && arguments[0] !== undefined ? arguments[0]: n;
因此,外部的'n'基本上已被新的var n
所取代。 - Keithletrec*
一样使用前面的值。想象一下你做了这样的事情:const test = (fun = (v) => v == 0 ? 0 : 1 + fun(v-1), v = 10) => fun(v)
。请注意,表达式在递归中使用了绑定的名称,如果fun
在闭包创建时不存在,这将无法工作。 - Sylwesterlet
或const
。 - Mulan