【问题标题】:How to write function-y accepting parameter-fct_x which accesses var-a which is required to be defined in function-y?如何编写函数-y接受参数-fct_x来访问需要在函数-y中定义的var-a?
【发布时间】:2014-12-16 13:05:32
【问题描述】:
function x() {
    return a + 1; // it can be anything accessing var-a.
}

function y(fct_x) {
    var a = 2;
    fct_x(); // exception: a is not defined
}

y(x);   // exception: see above
        // x is any function which will access var-a which is required to be defined in function-y

问题:如何写一个像上面这样的function-y,这样在function-y中调用fct_x()就不会抛出异常?
注意:fct_x 是访问 var-a 的任何函数(用户给定)。 var-a 没有在function-x 中定义,但需要在function-y 中定义。

提到Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?,我也试过this,但还是不行。

我为什么要问上面的问题: 这个问题来自“MongoDB mapReduce”,像这样: 地图缩减有 3 个属性和 28 个函数可用。 28 个函数之一是 emit(key,value)。 (See MongoDB doc).

举个例子,

function mapFunction() { emit(this.fieldA, this.fieldB) };
db.collection.mapReduce(mapFunction, reduceFunction, {...});  // calling mapReduce-function

mapFunction 中的 emit-function 未在 mapFunction 中定义。它在函数 db.collection.mapReduce 中的某处“提供”/“定义”。如何编写 function-db.collection.mapReduce 以便能够为 user-given-mapFunction 调用提供这样的发射函数?

[var a] 等价于 [function-emit]
[function y] 等价于 [function-mapReduce]
[function x] 等价于 [function-mapFunction]

【问题讨论】:

    标签: javascript mongodb


    【解决方案1】:

    如果我正确理解了您的问题,您正在寻找dynamic scoping。 Javascript 是词法范围的,因此要捕获变量,闭包必须在文本上在其范围内。否则,这是不可能的,不算或多或少的愚蠢技巧,例如:

    function makeClosure(context) {
        return function() {
            return context("a") + 1;
        };
    }
    
    function y(evalThis) {
        var a = 2;
    
        if(evalThis)
            return eval(evalThis);
    
        return makeClosure(y);
    }
    
    closure = y();
    document.write(closure()) // 3

    有关更多讨论和示例,另请参阅 Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?

    具体到您的 MongoDB 问题,在纯 JavaScript 中不可能将变量注入某个函数的作用域(同样,不求助于 eval)。但是 Mongo 的 map-reduce 是用 C++ 编写的,而不是用 JS 编写的,并且可以以任意方式操作范围:

    _scope->setFunction("emit", etc
    

    请参阅source

    为了完整起见,这里以eval 为例:

    function map(ary, fun) {
    
        // define some locals
        var LOCAL = 42;
    
        // re-evaluate the function within the scope
        eval("fun=" + fun);
    
        // now fun sees our locals
        return ary.map(fun);
    }
    
    document.write(
        map([1,2,3], function(x) { return x * LOCAL }) // [ 42, 84, 126 ]
    )

    【讨论】:

    • 非常感谢,乔治。答案很接近,但由于我的问题不清楚,所以不准确。我已经编辑了这个问题。请看一看。
    • 好的。 MongoDB 是用 C++ 编写的,它可以通过 _scope->setFunction("emit" 等注入作用域函数发射。但是,当在纯 JavaScript 中调用此函数时,我们可以为用户给定函数注入一些作用域函数/变量来访问吗? ? 我现在有了答案。看看我自己的答案。注意:诀窍是:在函数-y 中,#1。定义函数-x 使用的任何变量/函数。#2。重新创建函数-x this: [ var x = eval("("+String(fct_x)+")"); ]. #3. 运行函数-x: [ x(); ]. 现在 x() 访问那些定义的变量/函数在函数中。
    • @user2899992:很高兴你知道了!请注意,您的代码与我的第二个 sn-p 完全相同。
    【解决方案2】:

    Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?检查以下答案

    function x() {
        return a + 1; // it can be anything accessing var-a.
    }
    
    function y(fct_x) {
        var a = 2;
        var x = eval("(" + String(fct_x) + ")"); // eval(String(fct_x)) will return undefined.
                                                 // eval("(" + String(fct_x) + ")") will return a function
        console.log(x()); // 3 
    }
    
    y(x);   // exception: see above
            // x is any function which will access var-a which is required to be defined in function-y
    

    【讨论】:

      猜你喜欢
      • 2020-10-19
      • 1970-01-01
      • 2012-02-20
      • 2023-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-16
      • 2021-12-24
      相关资源
      最近更新 更多