javascript中的匿名递归|转载

阅读次数: 263

  • A+
所属分类:建站
javascript中的匿名递归|转载
<script>
    (
            (
                    (f)=>f(f)
            )
    (
            (f)=>
    (l)=>{
        console.log(l)
        if(l.length) f(f)(l.slice(1))
        console.log(l)
    }
    )
    )
    (
            [1,2,3]
    )
</script>

这是一个有趣的示例,这个例子包含以下特性:闭包),自执行函数,箭头函数,函数式编程和匿名递归。

控制台会打印如下:

(3) [1, 2, 3]
(2) [2, 3]
[3]
[]
[]
[3]
(2) [2, 3]
(3) [1, 2, 3]

在 JavaScript 中我们可以使用括号包裹任意数量的表达式:

('hey', 2+5, 'dev.to')

上面代码返回结果是 'dev.to',原因是 JavaScript 返回最后一个表达式作为结果。
使用括号 () 包裹一个匿名函数表示其结果就是 匿名函数 本身。
(function () { return 'hey' })

这本身并没有用处,因为匿名函数没有命名,无法被引用,除非在初始化的时候立即调用它。

就像是普通函数一样,我们可以在其后面添加括号 () 来进行调用。

(function () { return 'hey' })()

也可以使用箭头函数:

(() => 'hey')()

同样地,在匿名函数后添加括号 () 来执行函数,这被称为 自执行函数。

闭包

闭包) 指的是函数和该函数声明词法环境的组合。结合 箭头功能,我们可以定义如下:

var foo = (hi) => (dev) => hi + ' ' + dev

在控制台调用上述函数会打印 hey dev.to:
foo('hey')('dev.to')

注意,我们可以在内部函数作用域访问外部函数的参数 hi。

以下代码跟上述代码一样:

function foo (hi) {
return function (dev) { return hi + ' ' + dev }
}

自执行的版本如下:

(
 (hi) =>
   (
     (dev) => `${hi} ${dev}`
   )
   ('dev.to')
)
('hey')

首先,将 hey 作为参数 hi 的值传给最外层作用域的函数,然后这个函数返回另一个自执行函数。dev.to 作为参数 dev 的值传给内部函数,最后这个函数返回最终值:'hey dev.to'。

再深入一点

这个一个上述自执行函数的修改版本:

(
 (
   (dev) =>
     (hi) => `${hi} ${dev}`
 )
 ('dev.to')
)
('hey')

需要注意的是,自执行函数 和 闭包) 用作初始化和封装状态,接下来我们来看另外一个例子。

匿名递归

回到我们最初的例子,这次加点注释:

(
 (
   (f) => f(f) // 3.
 )
 (
   (f) => // 2.
     (l) => { // 4.
       console.log(l)
if (l.length) f(f)(l.slice(1))
       console.log(l)
     }
 )
)
(
 [1, 2, 3] // 1.
)

输入函数 [1, 2, 3] 传给最外层作用域

整个函数作为参数传给上面函数

这个函数接收下面函数作为参数 f 的值,然后自身调用

2.将被调用被作为 3.的结果然后返回函数 4. ,该函数是满足最外层作用域的函数,因此接收输入数组作为 l 参数的值

至于结果为什么是那样子,原因是在递归内部有一个对函数 f 的引用来接收输入数组 l。所以能那样调用:f(f)(l.slice(1))

注意,f 是一个闭包,所以我们只需要调用它就可以访问到操作输入数组的最里面的函数。

为了说明目的,第一个 console.log(l) 语句表示递归自上而下,第二个语句表示递归自下而上。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: