使用JSON格式化/解析js对象时,返回的方法中的函数作用域会丢失

时间:2014-09-07 14:59:06

标签: 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 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 is not defined

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

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; 
}

那么......问题是可以解决这种范围行为吗?据我所知,global.r在一个范围内分配f结果,但带有method函数的结果对象不保存变量实例,因为为该函数创建了另一个范围的JSON解析。 / p>

有什么想法吗?

P.S。请不要问为什么我需要这个:)只考虑可能的解决方案。 主要思想是以某种方式注入第一个模块(查看顶部body var)作为第二个模块中的变量(第二个函数的body var) 保存返回的方法的原始范围

谢谢!

1 个答案:

答案 0 :(得分:1)

  

是否可以解决此类范围行为?

没有。范围从外部无法访问,并且在函数序列化时必然会丢失。你只能字符串化#34; pure"像body这样的函数不引用任何自由变量。

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

  

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

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