Home > Net >  Is it possible to use closure scope of a function that receives data as a argument?
Is it possible to use closure scope of a function that receives data as a argument?

Time:12-02

There there is a function that expects a callback function that receives a data argument. I need a way to access foo inside the callback. From reading I found that closure scopes can be the solution, however I was struggling to find an example where the callback is receiving a data object as well (or any variable for that matter).

 const foo = 1;


 this.editor.functionThatExpectsCallback('genericString', (data) => {
       // do stuff with foo here, e.g.
       const bar = foo   data.num;      

       return bar;
  })

Basically the issue is foo is undefined inside the callback scope, and I need it to be defined, while still maintaining access to data as well. I would really appreciate any help I can get here. If you need more information I'd be happy to supply it.

CodePudding user response:

Your current code is correct because that is how scopes work - anything from an outer scope is visible within an inner one.

The only reason why it would not work is if the function was serialised and then deserialised - that completely removes all scope information:

{ //different scope here
  const foo = 1;
  const result = functionThatExpectsCallback('genericString', (data) => {
    // do stuff with foo here, e.g.
    console.log("foo is:", typeof foo);
    const bar = foo   data.num;

    return bar;
  });
  
  console.log(result);
}

//dummy implementation that serialises and deserialises a function to run it:

function functionThatExpectsCallback(arg, callback) {
  return runFromString(callback.toString());
}

function runFromString(strFunc) {
  const fn = eval(`(${strFunc})`);

  return fn({ num: 2 });
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

The first way to solve this is by checking the documentation of whatever library is used - it might provide a way to also send along extra arguments.

If that is not an option, then you would need to do it the dirty way and generate the function from string. You can use the Function constructor to do that

{ //different scope here
  const foo = 1;
  
  const generatedFunction = new Function("data", `
    // do stuff with foo here, e.g.
    const bar = ${foo}   data.num;

    return bar;
  `);
  
  const result = functionThatExpectsCallback('genericString', generatedFunction);
  
  console.log(result);
}

function functionThatExpectsCallback(arg, callback) {
  return runFromString(callback.toString());
}

function runFromString(strFunc) {
  const fn = eval(`(${strFunc})`);

  return fn({ num: 41 });
}
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

You have to be very careful because it is easy to introduce minor mistakes when generating a function from string and you can end up with invalid code. For example, if foo was a string foo = "hello" then the generated code would be const bar = hello data.num; which is invalid because hello would be a variable which was never defined, instead of the string literal "hello".

  • Related