javascript - 关于一次性自重定义函数模式

标签 javascript closures

考虑以下模式:

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_fooinner_foo 分别指定上面的外部函数和内部函数,即使代码不使用这些标识符。

outer_foo 的主体包括三个阶段(最后两个阶段各包含一个语句):

  1. 一些闭包变量的声明和初始化;
  2. 标识符foo的重新定义;
  3. 将最初传递给 outer_foo 的参数传递给 inner_foo,并返回结果。

outer_foo 的主体将最多执行一次,即第一次调用“名为 foo 的函数”(如果有的话)。此后,outer_foo 的主体将无法访问,所有对“名为 foo 的函数”的后续调用将导致 inner_foo 的执行。

一般来说,人们可能会设想这种模式的一些变体1,但我在这里谈论的基本方案的基本限制是:

  1. fooouter_foo2 的执行过程中恰好被重新定义一次;
  2. fooinner_foo 执行期间永远不会被重新定义。

(如果违反了这些基本约束,则所有赌注都将取消;这种情况超出了本问题的范围。)


我已经意识到这个方案的至少一个缺点:一些从业者认为自重定义函数令人困惑,不利于代码的可读性,和/或固有的低趣味,即使重新定义在一个完整的过程中只发生一次确定性方式,如上述方案中的情况。

我的问题是:

Does this scheme have any additional downsides, and if so, what are they?

I'm particularly interested in those downsides that are specific to 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 中恰好重新定义一次,而且这“确定性地”完成。当然,在 foo 的最终设置中与“确定性”(无论选择如何定义它)的任何偏差只会增加代码运行时行为的复杂性。不幸的是,我不知道如何在不陷入律师细节的迷宫的情况下使这个规定精确。我能做的最好的事情就是添加一个狡猾的——而且几乎是不连贯的——短语“越确定性越好”,并希望读者明白我的意思。然而,这个附加规定的唯一用途是排除不正当但完全不现实的场景(例如,foo 的最终值取决于随机过程的结果),所以我离开了

最佳答案

我可以想到您应该注意的另外两点:

  • 表现。编译器就像你提到的那些人。他们中的一些人会对这种模式感到困惑,并且他们可能无法像使用其他模式时那样对其进行优化。这可能是也可能不是问题,但您应该确保对其进行测试。
  • 违约。你说你希望 outer_foo 最多执行一次。事实可能并非如此!有人可能会传递它并在某处放置对它的引用,这样它在被调用时就不会变得无法访问。当然,这不太可能,但根据您的要求,您可能想要防范它。
    毕竟,这是一种损坏的设计,作为一个简单的别名 (var f = foo; f()) 永远不应该改变功能。确保所有消费者/用户都知道您在做什么,这样他们就不会被它绊倒。

关于javascript - 关于一次性自重定义函数模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32038503/

相关文章:

javascript - 尝试使用 ajax 将数据发送到 OOP 类

groovy - Groovy findAll 闭包中的复杂过滤逻辑

php - 使用匿名函数作为参数访问外部变量

javascript - 是否使用闭包,John Conway 的 Game of Life

javascript - 对 2 个数组进行排序/过滤

javascript - findOneAndUpdate Mongoose 查询返回旧数据库值

javascript - 如何使用 jQuery 以编程方式将 ng-pristine 设置为 ng-dirty?

javascript - 在javascript中递归复制二维数组的算法

ios - 如何在 swift 中使用 block /闭包

Rust 中作为可选函数参数的闭包