场景1
CL-USER> (list-contains 2 '(1 (2 3) 4))
The value (2 3) is not of the expected type NUMBER.
CL-USER> (defun tree-contains (n tree)
(cond ((null tree) nil)
((listp (car tree)) (or (tree-contains n (car tree))
(tree-contains n (cdr tree))))
((= (car tree) n) t)
(t (tree-contains n (cdr tree)))))
TREE-CONTAINS
CL-USER> (tree-contains 2 '(1 (2 3) 4))
T
场景2
function a(callback){
console.log("not calling callback");
}
a(function(callback_res){
console.log("callback_res", callback_res);
});
功能是否正在等待回调,并且不会在方案1中终止?但是,在两种情况下程序都会终止。
答案 0 :(得分:0)
问题不是安全,而是意图。如果一个函数接受回调,则可以在某个时候调用它。如果忽略接受的参数,则签名会产生误导。
这是一个不好的做法,因为函数签名给人关于函数工作方式的错误印象。
这还可能导致棉短绒中出现未使用参数警告。
函数将在等待回调并且不会在方案1中终止吗?
该函数不包含异步代码,不会等待任何东西。回调通常用于异步控制流中这一事实并不意味着它们本身就是异步的。
答案 1 :(得分:0)
函数将在等待回调并且不会在方案1中终止吗?
不。您显示的代码中没有任何东西等待回调被调用。
将回调传递给函数就像将整数传递给函数一样。该函数可以自由使用,也可以不使用,它对解释器的意义不外乎。 JS解释器没有“等待传递的回调被调用”的特殊逻辑。程序终止时,这没有任何效果。只是被调用的函数可以决定使用还是忽略函数的参数。
再举一个例子,通常将两个回调传递给一个函数,一个成功调用,一个错误调用:
function someFunc(successFn, errorFn) {
// do some operation and then call either successFn or errorFn
}
在这种情况下,很明显其中一个将被调用,而另一个则不会。从JS解释器的角度来看,不需要调用传递的回调。这纯粹是代码逻辑的特权。
现在,设计一个在调用签名中显示回调并且永远不要调用该回调的函数将不是一个好习惯。那简直是浪费,是一种误导性的设计。在许多情况下,有时会调用回调,有时又不取决于情况。 Array.prototype.forEach
就是这样一个例子。如果在空数组上调用array.forEach(fn)
,则永远不会调用该回调。但是,当然,如果在非空数组上调用它,则会被调用。
如果您的函数执行异步操作,并且回调的重点是在异步操作完成时进行通信,以及它是否以错误或值结束,那么通常使用不好的代码路径是永远不好的形式之所以调用回调函数,是因为调用者自然会认为该回调函数正在被最终调用。我可以想象可能会有一些例外,但是最好用功能的文档/注释将它们很好地记录下来。
对于异步操作,您的问题使我想起了一些问题:Do never resolved promises cause memory leak?,这可能对阅读很有帮助。