- A+
所属分类:建站
<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) 语句表示递归自上而下,第二个语句表示递归自下而上。
- 我的微信
- 这是我的微信扫一扫
-
- 我的微信公众号
- 我的微信公众号扫一扫
-