如何在 JavaScript 中模拟 let 表达式?

Aad*_*hah 2 javascript functional-programming let ecmascript-6

考虑以下实现take

const take = (n, [x, ...xs]) =>
    n === 0 || x === undefined ?
    [] : [x, ...take(n - 1, xs)];

console.log(take(7, [1, 2, 3, 4, 5])); // [1, 2, 3, 4, 5]
console.log(take(3, [1, 2, 3, 4, 5])); // [1, 2, 3]
console.log(take(1, [undefined, 1]));  // []
Run Code Online (Sandbox Code Playgroud)

如您所见,它不适用于数组,undefined因为x === undefined这不是测试数组是否为空的最佳方法。下面的代码修复了这个问题:

const take = (n, xs) =>
    n === 0 || xs.length === 0 ?
    [] : [xs[0], ...take(n - 1, xs.slice(1))];

console.log(take(7, [1, 2, 3, 4, 5])); // [1, 2, 3, 4, 5]
console.log(take(3, [1, 2, 3, 4, 5])); // [1, 2, 3]
console.log(take(1, [undefined, 1]));  // [undefined]
Run Code Online (Sandbox Code Playgroud)

然而,写作xs[0]xs.slice(1)没有那么优雅。此外,如果您需要多次使用它们也是有问题的。要么你必须复制代码并做不必要的额外工作,要么你必须创建一个块作用域,定义常量并使用 return 关键字。

最好的解决方案是使用let 表达式。不幸的是,JavaScript 没有它们。那么,如何在 JavaScript 中模拟 let 表达式呢?

Aad*_*hah 6

在 Lisp 中,let 表达式只是左左 lambda(即立即调用的函数表达式)的语法糖。例如,考虑:

(let ([x 1]
      [y 2])
  (+ x y))

; This is syntactic sugar for:

((lambda (x y)
    (+ x y))
  1 2)
Run Code Online (Sandbox Code Playgroud)

在 ES6 中,我们可以使用箭头函数默认参数来创建一个类似于 let 表达式的 IIFE,如下所示:

const z = ((x = 1, y = 2) => x + y)();

console.log(z);
Run Code Online (Sandbox Code Playgroud)

使用这个 hack,我们可以定义take如下:

const take = (n, xxs) =>
    n === 0 || xxs.length === 0 ?
    [] : (([x, ...xs] = xxs) => [x, ...take(n - 1, xs)])();

console.log(take(7, [1, 2, 3, 4, 5])); // [1, 2, 3, 4, 5]
console.log(take(3, [1, 2, 3, 4, 5])); // [1, 2, 3]
console.log(take(1, [undefined, 1]));  // [undefined]
Run Code Online (Sandbox Code Playgroud)

希望有帮助。

  • @Bergi 这很老套,但我喜欢它,因为它比 `(() => {const x = 1; const y = 2; return x + y;})()` 干净得多 (2认同)