Javascript 当使用JSON对js对象进行strigiff/解析时,返回的方法中会丢失函数范围

Javascript 当使用JSON对js对象进行strigiff/解析时,返回的方法中会丢失函数范围,javascript,json,function,scope,Javascript,Json,Function,Scope,我有这样一个有点疯狂的例子,但对于那些javascript函数领域的专家来说,这似乎是一个很好的练习: (function (global) { // our module number one var body = function () { var someVar = 'some test text'; return { method: function () { return someVar; // this will und

我有这样一个有点疯狂的例子,但对于那些javascript函数领域的专家来说,这似乎是一个很好的练习:

(function (global) {
  // our module number one
  var body = function () {
    var someVar = 'some test text';
    return {
        method: function () {
            return someVar; // this will undefined when call this method in second module
        }
    };
  };
  var f = new Function([' return (', body, ')();'].join(''));
  global.r = f();
})(window);

(function (global) {
  // our module two
  var body = function () {
    // dep variable is injected on the fly with `new Function`
    dep.method(); // will throw `Reference Error: someVar is not defined`
  };

  // helper to propertly transform functions in JSON.stringify
  function transformFuncs (key, val) {
    if (typeof val === 'function') {
        return val.toString().replace(/(\t|\n|\r)/gm, '').replace(/("|')/gm, '\\"');
    }
    return val;
  }
  // injecting our first module inside
  var vars = ['var ', 'dep', ' = JSON.parse(\'', JSON.stringify(global.r, transformFuncs), '\', function (key, value) { if (value && typeof value === "string" && value.substr(0,8) == "function") { var startBody = value.indexOf("{") + 1; var endBody = value.lastIndexOf("}"); var startArgs = value.indexOf("(") + 1; var endArgs = value.indexOf(")"); return new Function(value.substring(startArgs, endArgs), value.substring(startBody, endBody)); } return value; });'].join('');
  // as variable
  var f2 = new Function([vars, ' return (', body, ')();'].join(''));
  global.r2 = f2();
})(window);
如果在某处运行此代码,您将看到抛出异常
ReferenceError:someVar未定义

所以基本上这里发生了什么-我们创建一些模块,然后尝试将其作为变量注入另一个模块中。在
JSON.parse
中用于正确获取字符串化函数的函数如下所示(如果您好奇):

所以。。问题是有可能绕过这种范围行为吗?据我所知,
global.r
在一个作用域中分配了
f
result,但是
method
函数的结果对象没有保存变量实例,因为在JSON解析时,为该函数创建了另一个作用域

有什么想法吗

p.S.请不要问我为什么需要这个:)想想可能的解决方案主要思想是以某种方式将模块1号(查看顶部
body
var)作为第二个模块内的变量
body
var第二个函数)保存返回的方法的原始范围

谢谢

有可能绕过这种范围行为吗

不可以。作用域从外部无法访问,并且在函数序列化时它们必然会丢失。您只能字符串化不引用任何自由变量的“纯”函数,如
body

这也是JSON格式不包含函数的原因

其主要思想是以某种方式将模块1作为变量注入到第二个模块中,从而保存返回的方法的原始范围


注入引用,而不是字符串。依赖注入并不是什么神奇的东西,各种JavaScript模块加载器都能做到。

不,这是不可能的。由于要将函数转换为字符串,因此将失去创建该函数的环境。此信息在运行时不可访问,因此无法以某种方式序列化它。静态分析可以取得一些进展,但这只适用于源代码中包含的值,而不是在运行时创建的值。所以走这条路可能太费劲了。请解释一下这些
新功能是什么。至少可以完全省略
f
,我不确定
f2
是否正确,但我想这也不是必需的。为了简化,请将它们从代码中删除,或者对它们所做的操作进行注释(尤其是
f2
中的一行代码)。@Bergi此示例只是我正在处理的代码库的简化版本。不要太注意它<代码>新函数
需要一些东西,因为在我的例子中(这在示例中是常见的),我是用来循环不同模块的hashmap,并将它们保存为变量字符串,然后注入。是的,解决方案就是不在hashmap中存储字符串。引用中我无法解决的问题是,我无法将某个模块作为变量注入另一个模块中(将var name的依赖项名称保留在第二个模块中)将其作为函数参数注入。但也许我不明白你的意思?我的意思是,例如,我有一些模块依赖项的哈希映射。我想将模块函数中的每个依赖项都作为具有哈希属性名称的变量注入,而不是作为函数参数注入(请看第二个
body
-
r
作为var随
新函数动态注入)。我已经更新了示例代码-现在它是
dep
,以获得更多的许可。变量(namable via
eval
)和函数参数(namable via
new function
)之间没有太大的区别-您可以自由地使用它们来获取范围中任意命名的标识符。您只需要执行
var dep=modulesHash[“r”]
而不是
var dep=eval(stringifiedModules[“r”])
function (key, value) { 
  if (value && typeof value === "string" && value.substr(0,8) == "function") { 
    var startBody = value.indexOf("{") + 1; 
    var endBody = value.lastIndexOf("}"); 
    var startArgs = value.indexOf("(") + 1; 
    var endArgs = value.indexOf(")"); 
    return new Function(value.substring(startArgs, endArgs), value.substring(startBody, endBody)); 
  } 
  return value; 
}