考虑以下模式:
function foo /* aka outer_foo */ () {
// === stage 1 ===
// declaration and initialization of closure variables
var ... <CLOSURE_VARS> ...;
// initialization of CLOSURE_VARS
// (possibly expensive and/or depending on values known only at run-time)
// === stage 2 ===
// one-time redefinition of foo
foo = function /* inner_foo */ ( arg0, ... ) {
var results;
// code computing value of results based on CLOSURE_VARS, arg0, ...
// foo is never modified here
return results;
};
// === stage 3 ===
// invocation of inner function and returning of result
return foo.apply( this, arguments );
}
为方便起见,我将使用术语 outer_foo 和 inner_foo 分别指定上面的外部和内部函数,即使代码不使用这些标识符。
outer_foo 的主体包含三个阶段(最后两个阶段由每个单个语句组成):
foo
; outer_foo 的主体最多会被执行一次,即第一次&#34;名为foo
&#34;的函数被叫,如果它发生了。此后, outer_foo 的主体将无法访问,并且所有后续调用&#34;名为foo
&#34;的函数将导致执行 inner_foo 。
一般来说,人们可能会想到这种模式的一些变化 1 ,但我在这里讨论的基本方案的基本限制是:
foo
2 期间,outer_foo
只被重新定义一次; foo
期间,inner_foo
永远不会重新定义。(如果违反了这些基本限制,所有投注都会被取消;这种情况超出了本问题的范围。)
我已经意识到这个方案至少有一个缺点:一些从业者认为自我重新定义的功能令人困惑,不利于代码可读性,和/或本质上很差,即使重新定义只发生一次完全确定性方式,如上述方案中的情况。
我的问题是:
此方案是否有任何附加缺点,如果是,那么它们是什么?
我对那些特定于JavaScript的缺点特别感兴趣。
1 例如,
function foo /* aka outer_foo */ () {
var inner_foo, ... <CLOSURE_VARS> ...;
if ( some_deterministic_test() ) {
inner_foo = function ( arg0, ... ) {
// etc.
}
}
else {
inner_foo = function ( arg0, ... ) {
// etc.
}
}
foo = inner_foo;
return foo.apply( this, arguments );
}
在此变体中,最终分配给foo
的函数取决于在运行时执行的某些测试。
2 这里很容易规定foo
不仅必须在 outer_foo 内完全重新定义一次,而且这可以确定性地完成&#34;。当然,任何偏离&#34;决定论&#34; (但是选择定义它)在foo
的最终设置中只能增加代码运行时行为的复杂性。不幸的是,我不知道如何使这个规定准确无误,而不会陷入律师般的细枝末节。我能做的最好的事情就是添加狡猾和边缘不连贯的短语&#34;越确定越好,#34;并希望读者明白我的观点。然而,这个额外规定的唯一用途是排除不正当但完全不切实际的情景(例如,foo
的最终值取决于随机过程的结果),所以我把它排除在外。功能
答案 0 :(得分:1)
我可以想到你应该注意的两点:
var f = foo; f()
)永远不应改变功能。确保所有消费者/用户都知道你在做什么,这样他们就不会绊倒它。