最近我开始接触 javascript 生态系统。在使用 javascript 的回调一段时间后,我开始问自己 javascript 解释器是否能够对回调参数进行条件评估。让我们以下面两个例子为例:
var a = 1;
var b = 2;
// example 1
abc.func(a, b, function (res) {
// do something with res
});
// example 2
abc.func(a, b, function () {
// do something
});
据我了解,Javascript 使用 arguments
对象来跟踪传递给函数的内容。这与函数定义是什么无关。所以假设:
abc.func = function (a, b, cb) {
// do stuff
var res = {};
// Expensive computation to populate res
cb(res);
}
在两个示例 (1, 2) 中,res
对象都将传递给 arguments[0]
。在示例 1 res === arguments[0]
中,因为定义了 res
参数。
让我们假设计算 res
是昂贵的。在示例 1 中,可以进行此计算,因为使用了 res
对象。在示例 2 中,由于未使用 res
对象,因此进行该计算确实没有意义。虽然,由于需要填充 arguments
对象,在这两种情况下,填充 res
的计算都已完成。这是正确的吗?
假设这是真的,这似乎是一种(潜在的)巨大浪费。为什么要计算超出范围并被垃圾收集的东西?想想所有使用回调的库。他们中的很多人将多个参数发送回回调函数,但有时一个也没有用到。
有没有办法防止这种行为。本质上使 Javascript 解释器足够聪明,不会计算那些将变成未使用参数的特定变量?所以在示例 2 中,res
对象实际上不会被计算,因为它永远不会被实际使用。
据我所知,在此之前使用了这样的东西:
function xyz(a, b /*, rest */)
// use arguments to iterate over rest
}
因此默认情况下仍然计算这些参数是有意义的。现在让我们期待 ECMAScript 2015。这将包括 ...rest
要定义的参数。那么对于支持新版本的引擎,有没有办法开启条件求值呢?这会更有意义,因为现在有一种方法可以明确要求评估并将所有额外参数传递给函数。
最佳答案
不,JavaScript 不是一种懒惰的按名称调用的语言。这主要是因为表达式可能有副作用,而 ES 标准要求它们按照程序员期望的顺序执行。
是的,JS 引擎很聪明。如果他们确实检测到代码没有执行副作用,并且它的结果没有在任何地方使用,它只是转储它们(dead code elimination)。我不确定这是否适用于跨函数边界,我猜它不会,但如果您处于热代码路径中并且调用确实被内联,则它可能会被优化。
因此,如果您知道自己正在进行繁重的计算,您可能希望通过传递 thunk 使其显式惰性化。 .在急切评估的语言中,这通常由不带参数的函数简单表示。在你的情况下:
abc.func = function (a, b, cb) {
// do stuff
var res = {};
cb(() => {
// Expensive computation to populate res
return res;
});
}
// example 1
abc.func(a, b, function(getRes) {
var res = getRes();
// do something with res
});
// example 2
abc.func(a, b, function() {
// no heavy computation
// do something
});
关于javascript - 回调参数的条件评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32301554/