1
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

Question: how to write a function-y like above so that calling fct_x() within function-y will not throw exception?
Note: fct_x is any function (user given) which accesses var-a. The var-a not defined in function-x, but is required to be defined in function-y.

With referring to Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?, I have tried like this, but it does not work.

Why I ask above question: This question comes from "MongoDB mapReduce", like this: There are 3 properties and 28 functions available for the map-reduction. One of the 28 function is emit(key,value). (See MongoDB doc).

Take this example,

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

The emit-function within mapFunction is not defined in mapFunction. It is "provided"/"defined" somewhere within function db.collection.mapReduce. How function-db.collection.mapReduce is written to be able to proivde such emit-function for a user-given-mapFunction to call?

[var a] equivalent to [function-emit]
[function y] equivalent to [function-mapReduce]
[function x] equivalent to [function-mapFunction]

Community
  • 1
  • 1

2 Answers2

1

If I understood your question correctly, you're looking for dynamic scoping. Javascript is lexically scoped, so to capture a variable, the closure must be textually within its scope. Otherwise, this is not possible, not counting more or less silly tricks like, for example:

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

See also Is it possible to achieve dynamic scoping in JavaScript without resorting to eval? for more discussion and examples.

As to your MongoDB question specifically, it's not possible in pure javascript to inject a variable into some function's scope (again, without resorting to eval). But Mongo's map-reduce is written in C++, not in JS, and can manipulate the scope in arbitrary ways:

_scope->setFunction("emit", etc

See the source.

For completeness, here's an example with 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 ]
)
Community
  • 1
  • 1
georg
  • 211,518
  • 52
  • 313
  • 390
  • Thanks you very much, georg. The answer is close, but not exact due to my question is not clear. I have edited the question. Please have a look. – Johnson Cheung HK06 Dec 16 '14 at 15:00
  • OK. MongoDB is written in c++ which can inject scoped function-emit by _scope->setFunction("emit", etc .. But, can we inject some scoped functions/variables for a user given function to access when calling this function in pure-javascript? I have the answer now. See my own answer. Note: the trick is: within function-y, #1. define whatever varaibles/functions to be used by function-x. #2. Re-create the function-x like this: [ var x = eval("("+String(fct_x)+")"); ]. #3. run the function-x: [ x(); ]. Now x() accessing those variables/functions defined in function-y. – Johnson Cheung HK06 Dec 16 '14 at 17:33
  • @user2899992: glad you figured it out! Note that your code is exactly the same as my second snippet. – georg Dec 16 '14 at 17:35
0

Following answer is inspected by 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
Community
  • 1
  • 1