Javascript中的函数如何“延迟求值”?当想要避免急于评价
How do functions in Javascript "delay evaluation" when wanting to avoid eager evaluation?
这个例子是从书中摘取的,Javascript Allonge。本课题涉及控制流运算符和函数参数的求值。
const or = (a, b) => a || b
const and = (a, b) => a && b
const even = (n) =>
or(n === 0, and(n !== 1, even(n - 2)))
even(42)
//=> Maximum call stack size exceeded.
书中指出这将导致无限递归。我相信我理解这部分。因为所有参数都将被求值,即使or()中的a参数为真,b参数仍将被求值(即在even()下调用or()函数时)。和()也是如此。偶数(n -2)参数最终将被反复求值,n为2,0,-2,-4…
作为解决方案,它说可以将匿名函数作为参数传递。
const or = (a, b) => a() || b()
const and = (a, b) => a() && b()
const even = (n) =>
or(() => n === 0, () => and(() => n !== 1, () => even(n - 2)))
even(7)
//=> false
现在我明白了代码是如何被重写来处理包含原始表达式的匿名函数的,但我不明白这是如何"延迟求值"的。因为匿名函数仍然是或()和甚至()函数的参数,所以如何阻止它们求值并得到与前面代码相同的结果呢?
因为匿名函数仍然是or()和even()函数的参数,那么如何防止它们计算并达到与前面代码相同的结果呢?
or()
/and()
调用的参数确实被求值。但这意味着函数表达式被求值(到一个函数),然后传递给or
/and
,而不是实际调用函数。它只在函数内部的a()
/b()
中被调用,并且只在实际需要时(因为操作符的短路)才被调用——这才是递归调用的实际位置。
顺便说一下,这个概念也被称为坦克
在even()
的两个版本中,必须在调用or()
之前计算对or()
的外部调用的参数。因此,在第一个版本中:
const even = (n) =>
or(n === 0, and(n !== 1, even(n - 2)))
必须对形参表达式求值,第二个实参将触发无限递归。
然而,在第二个版本中,or()
和and()
函数期望被传递的函数返回值,而不是值本身。因此,在代码进入or()
和and()
的实现之前,这些函数不会被调用。因为or()
和and()
函数是为了利用JavaScript的短路逻辑运算符而编写的,所以没有无限递归。
因此:
const even = (n) =>
or(() => n === 0, () => and(() => n !== 1, () => even(n - 2)))
仍然需要计算or()
的实际参数,但参数只是函数—它们说明了如何获取一个值,但是在调用之前它们实际上什么都不做。
操作符||
和&&
使用短路求值:
短路评估、最小评估或麦卡锡评估表示编程中某些布尔运算符的语义只执行或求值第二个参数的语言如果第一个参数不足以确定的值表达
例如,如果有a() || b()
,调用a
返回true
,则不会调用b
函数。
然而,对于or
和and
函数,您无法实现此行为,因为它们是函数,而不是操作符。传递给函数的形参在调用函数之前求值。
因此,or(a(), b())
将同时调用a
和b
,即使前者返回true
。
传递函数更有效,因为函数在调用之前不会运行。因此,不是比较它们返回的值,而是将函数本身传递给or
或and
,由于它们是使用操作符||
或&&
实现的,因此函数的调用将被短路计算。
- 如何将HTML id分配给元素,以及如何将JavaScript应用于元素
- 我可以获得相对于被点击元素的确切点击位置吗
- 如果使用 lodash 将属性存在于另一个对象中,则向对象添加属性
- 如何包含特定于每个视图angularjs的javascript文件
- Javascript日期格式类似于ISO,但本地
- toBoolean方法类似于toString
- es6 相当于下划线查找位置
- str.split(someString).join(someOtherString)是否等效于替换
- 州和城市选择框类似于国家细分页面
- Youtube API v3 无法回复或评价任何评论
- “评价这个应用程序”谷歌播放商店链接在离子应用程序
- 培根的评价模型是什么.js
- AngularJs对ng节目的评价相当缓慢
- 点击锚标签,我显示客户评价DIV,但高度没有扩大
- Javascript中的函数如何“延迟求值”?当想要避免急于评价
- 如何获得半星评价
- 对可点击文本进行正面和负面评价
- 评价图像系统
- 如何评价2015年谷歌发布的Polymer 1.0
- 调用Facebook共享代码从php一旦用户评价任何项目