javascript - 我需要帮助了解其余和传播运算符

标签 javascript ecmascript-6

这是代码:

const Pipe = (...fns) => fns.reduce((f,g) => (...args) => g(f(...args)));

所以通过 (...fns) fns 参数变成了一个数组,对吗?在这部分:
 (f,g) => (...args)

args 是从哪里来的?是否有默认的 args 参数?我无法阅读这部分:
(...args) => g(f(...args))

我只是无法用这种嵌套来包裹我的头,而 reduce 在这里所做的事情是如此令人困惑。

最佳答案

您的第一个问题是您正在处理 pipe 的错误实现– 第二个问题是新 JavaScript 中有多种扩展语法,并且(对于初学者)并不总是很清楚在哪里使用哪一种语法

休息参数

一个 rest 参数将提供的参数收集到一个数组中的函数。这取代了旧的 arguments JavaScript 过去的对象

const f = (...xs) =>
  xs
  
console.log(f())    // []
console.log(f(1))   // [1]
console.log(f(1,2)) // [1,2]



传播论据

传播参数允许您将数组(或任何可迭代的)作为参数传播给函数调用。这替换了(几乎所有)Function.prototype.apply 的实例。

const g = (a,b,c) =>
  a + b + c
  
const args = [1,2,3]

console.log(g(...args)) // 6



为什么pipe不好

这不是一个完整的功能 – pipe s 域是 [Function] (函数数组),但如果使用空函数数组,此实现将产生错误(TypeError: Reduce of empty array with no initial value)

这可能不会立即显现出来,但它可能以多种方式出现。最值得注意的是,当要应用的函数列表是在程序的其他地方创建的数组并最终为空时,Pipe灾难性地失败
const foo = Pipe()
foo(1)
// TypeError: Reduce of empty array with no initial value

const funcs = []
Pipe(...funcs) (1)
// TypeError: Reduce of empty array with no initial value

Pipe.apply(null, funcs) (1)
// TypeError: Reduce of empty array with no initial value

Pipe.call(null) (1)
// TypeError: Reduce of empty array with no initial value

重新实现 pipe

这是无数的实现之一,但它应该更容易理解。我们有一种使用 rest 参数和一种使用 spread 参数。最重要的是,pipe 总是 返回一个函数

const pipe = (f,...fs) => x =>
  f === undefined ? x : pipe(...fs) (f(x))
  
const foo = pipe(
  x => x + 1,
  x => x * 2,
  x => x * x,
  console.log
)

foo(0) // 4
foo(1) // 16
foo(2) // 36

// empty pipe is ok
const bar = pipe()
console.log(bar(2)) // 2



“但我听说递归很糟糕”

好的,所以如果你要传递数千个函数,你可能会遇到堆栈溢出。在这种情况下,您可以使用堆栈安全的 Array.prototype.reduce (或 reduceRight )就像您原来的帖子一样。

这次不是在 pipe 内做所有事情。 ,我将把问题分解成更小的部分。每个部分都有不同的用途,pipe现在只关心零件如何组合在一起。

const comp = (f,g) => x =>
  f(g(x))

const identity = x =>
  x
  
const pipe = (...fs) =>
  fs.reduceRight(comp, identity)

const foo = pipe(
  x => x + 1,
  x => x * 2,
  x => x * x,
  console.log
)

foo(0) // 4
foo(1) // 16
foo(2) // 36

// empty pipe is ok
const bar = pipe()
console.log(bar(2)) // 2



“我真的只是想了解我帖子中的代码”

好的,让我们逐步了解您的 pipe功能,看看发生了什么。因为reduce将多次调用 reduce 函数,我将为 args 使用唯一的重命名每一次
// given
const Pipe = (...fns) => fns.reduce((f,g) => (...args) => g(f(...args)));

// evaluate
Pipe(a,b,c,d)

// environment:
fns = [a,b,c,d]

// reduce iteration 1 (renamed `args` to `x`)
(...x) => b(a(...x))

// reduce iteration 2 (renamed `args` to `y`)
(...y) => c((...x) => b(a(...x))(...y))

// reduce iteration 3 (renamed `args` to `z`)
(...z) => d((...y) => c((...x) => b(a(...x))(...y))(...z))

那么当应用该功能时会发生什么?让我们看看当我们应用 Pipe(a,b,c,d) 的结果时有一些论据Q
// return value of Pipe(a,b,c,d) applied to `Q`
(...z) => d((...y) => c((...x) => b(a(...x))(...y))(...z)) (Q)

// substitute ...z for [Q]
d((...y) => c((...x) => b(a(...x))(...y))(...[Q]))

// spread [Q]
d((...y) => c((...x) => b(a(...x))(...y))(Q))

// substitute ...y for [Q]
d(c((...x) => b(a(...x))(...[Q]))

// spread [Q]
d(c((...x) => b(a(...x))(Q))

// substitute ...x for [Q]
d(c(b(a(...[Q])))

// spread [Q]
d(c(b(a(Q)))

所以,正如我们所料
// run
Pipe(a,b,c,d)(Q)

// evalutes to
d(c(b(a(Q))))

补充阅读

我写了很多关于函数组合的文章。我鼓励你探索其中一些相关的问题/我已经写了很多关于函数组合的文章。我鼓励您探索其中一些相关的问题/答案

如果有的话,您可能会看到 compose 的不同实现。 (或 pipeflow 等)在每个答案中。也许其中之一会与您的更高良心交谈!
  • How to understand curry and function composition using Lodash flow?
  • lodash curry does not work on function returned by flow; lodash FP enough for FP?
  • functional composition of a boolean 'not' function (not a boolean value)
  • How to compose functions of varying arity using Lodash flow?
  • How to reconcile Javascript with currying and function composition
  • 关于javascript - 我需要帮助了解其余和传播运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44275396/

    相关文章:

    javascript - Jquery 1.5.2 替代 .on() 函数

    javascript - 在 React 组件的属性中插入 JSON?

    javascript - node.js(ES6/Babel)中 import X 和 import * as X 的区别?

    javascript - 找不到导出——但名称仍然有效

    javascript - 为什么这个非常棘手的计算属性名称函数会按照它的方式工作?

    javascript - Express服务器响应是一个流,如何使其成为字符串/json

    javascript - 同步两个具有不同模型的文本框

    javascript - 为什么 splice 返回的是字符串而不是数组?

    javascript - HTML DOM,ids vs 无 ids?

    javascript - 如何在 JavaScript 中实现类自由继承(Crockford 风格)