【问题标题】:JavaScript pass scope to another functionJavaScript 将作用域传递给另一个函数
【发布时间】:2011-09-14 23:39:13
【问题描述】:

是否有可能以某种方式将函数的作用域传递给另一个函数?

例如,

function a(){
   var x = 5;
   var obj = {..};
   b(<my-scope>);
}

function b(){
   //access x or obj....
}

我宁愿直接访问变量,即不使用this.athis.obj之类的任何东西,而直接使用xobj

【问题讨论】:

  • 范围是指方法还是所有在 a() 变量中初始化的值等?顺便说一句(+1)问得好。
  • 此外,如果您发现问题的答案很有用,您应该接受它们的答案(请参阅那里有一个勾号)并使用upvotes。它将帮助您获得更多答案。

标签: javascript node.js closures scope serverside-javascript


【解决方案1】:

你真的只能用 eval 来做到这一点。下面将给出函数b函数a的作用域

  function a(){
     var x = 5;
     var obj = {x};
     eval('('+b.toString()+'())');
  }
  
  function b(){
     //access x or obj....
     console.log(x);
  }
  
  a();  //5

【讨论】:

    【解决方案2】:

    真正访问函数a 的私有作用域的唯一方法是在a 内声明b,这样它就形成了一个允许隐式访问a 变量的闭包。

    这里有一些选项供您选择。

    直接访问

    1. a 内声明b

      function a() {
         var x = 5,
            obj = {};
         function b(){
            // access x or obj...
         }
         b();
      }
      
      a();
      
    2. 如果您不想将b 放在a 中,那么您可以将它们都放在更大的容器范围内:

      function container() {
         var x, obj;
         function a(){
            x = 5;
            obj = {..};
            b();
         }
         function b(){
            // access x or obj...
         }
      }
      
      container.a();
      

    这些是您可以直接在b 中使用a 的变量的唯一方法,而无需一些额外的代码来移动。如果您满足于一点“帮助”和/或间接性,这里还有一些想法。

    间接访问

    1. 您可以只将变量作为参数传递,但除了对象的属性外没有写入权限:

      function a() {
         var x = 5,
            obj = {};
         b(x, obj);
      }
      
      function b(x, obj){
         // access x or obj...
         // changing x here won't change x in a, but you can modify properties of obj
      }
      
      a();
      

      作为一种变体,您可以通过将更新后的值传回a 来获得写入权限,如下所示:

      // in a:
      var ret = b(x, obj);
      x = ret.x;
      obj = ret.obj;
      
      // in b:
      return {x : x, obj : obj};
      
    2. 你可以传递b一个带有getter和setter的对象,可以访问a的私有变量:

      function a(){
         var x = 5,
            obj = {..},
            translator = {
               getX : function() {return x;},
               setX : function(value) {x = value;},
               getObj : function() {return obj;},
               setObj : function(value) {obj = value;}
            };
         b(translator);
      }
      
      function b(t){
         var x = t.getX(),
            obj = t.getObj();
      
         // use x or obj...
         t.setX(x);
         t.setObj(obj);
      
         // or you can just directly modify obj's properties:
         obj.key = value;
      }
      
      a();
      

      getter 和 setter 可以是公共的,分配给 athis 对象,但这样它们只有在 a 中明确给出时才能访问。

    3. 您可以将变量放在一个对象中并传递该对象:

      function a(){
         var v = {
            x : 5,
            obj : {}
         };
         b(v);
      }
      
      function b(v){
         // access v.x or v.obj...
         // or set new local x and obj variables to these and use them.
      }
      
      a();
      

      作为一种变体,您可以在调用时构造对象:

      function a(){
         var x = 5,
            obj = {};
         b({x : x, obj: obj});
      }
      
      function b(v){
         // access v.x or v.obj...
         // or set new local x and obj variables to these and use them.
      }
      
      a();
      

    【讨论】:

      【解决方案3】:

      你不能“通过范围”...不是我所知道的。
      您可以使用applycall 传递函数所引用的对象,并将当前对象(this)作为第一个参数发送,而不仅仅是调用函数:

      function b(){
          alert(this.x);
      }
      function a(){
          this.x = 2;
          b.call(this);
      }
      

      函数访问特定范围的唯一方法是在该范围内声明。
      有点棘手。
      这会导致类似:

      function a(){
          var x = 1;
          function b(){
              alert(x);
          }
      }
      

      但这会破坏目的。

      【讨论】:

      • @Erik 那是多余的。如果我想将变量作为参数传递,我不需要作用域。
      • @gion 查看我的答案(第三个代码块)。我提出的建议与将它们作为参数传递有点不同。
      • @Erik 我知道。您想传递一个可以“模拟”范围的对象。我并不是说它是错误的或它不起作用。这很好,但不是这个问题的答案。
      • @gion 我发现提供更多选择而不是只回答确切的问题很有帮助。例如,“您可以使用动态 SQL 执行此操作,但您可能不应该这样做,这里有其他选项”。无论如何,如果你是这么想的,我没有给你投反对票。
      • @Erik:它与 node.js 无关。请参阅java-samples.com/showtutorial.php?tutorialid=829 了解更多信息
      【解决方案4】:

      我认为您可以做的最简单的事情是变量从一个范围传递到该范围之外的函数。如果您通过引用传递(如对象),b '访问'它(参见下面的 obj.someprop):

      function a(){
         var x = 5;
         var obj = {someprop : 1};
         b(x, obj);
         alert(x); => 5
         alert(obj.someprop); //=> 'otherval'
      }
      function b(aa,obj){
         x += 1; //won't affect x in function a, because x is passed by value
         obj.someprop = 'otherval'; //change obj in function a, is passed by reference
      }
      

      【讨论】:

      • 如给定的,您的b 函数将访问全局aobj,而不是a 中的那些。
      • 是的,忘记了 b() 中的参数,编辑了,顺便重命名了 var a,因为这可能与函数名冲突(jshint.com 抱怨)
      【解决方案5】:

      你有没有尝试过这样的事情:

      function a(){
         var x = 5;
         var obj = {..};
         b(this);
      }
      function b(fnA){
         //access x or obj....
         fnA.obj = 6;
      }
      

      如果您可以将函数 B 视为方法函数 A,请执行以下操作:

      function a(){
         var x = 5;
         var obj = {..};
         b(this);
      
         this.b = function (){
            // "this" keyword is still === function a
         }
      }
      

      【讨论】:

      • 1.根本不需要使用this。只需在a 内声明b 将自动授予b 访问a 的私有变量的权限。 2. 在b 中使用this 关键字将无法访问私有变量,因此this.obj 将在b 中未定义。
      【解决方案6】:
      function a(){
         var x = 5;
         var obj = {..};
         var b = function()
         {
              document.println(x);
         }
         b.call();
      }
      

      【讨论】:

      • 这不是最好的答案,但它是一个很好的答案。传递作用域的一种方法是在该作用域中定义函数,所以不要反对这个
      • Shawn 不需要b.call();。直接b();即可。
      【解决方案7】:
      function a(){
         this.x = 5;
         this.obj = {..};
         var self = this;
         b(self);
      }
      function b(scope){
         //access x or obj....
      
      }
      

      【讨论】:

      • 这是上下文,而不是范围。
      【解决方案8】:

      正如其他人所说,您不能像那样传递范围。但是,您可以使用自执行匿名函数正确地确定变量的范围(或者如果您是迂腐的,则立即执行):

      (function(){
          var x = 5;
          var obj = {x:x};
          module.a = function(){
              module.b();
          };
          module.b = function(){
              alert(obj.x);    
          };
      }());
      
      a();
      

      【讨论】:

      • 当人们不阅读问题并使用浏览器js时,这很烦人。这与在仅 JavaScript 问题中使用 jQuery 一样糟糕。 thismodule 而不是 window 所以写信给它。我还强烈建议再次覆盖global,因为那是node.js 中的真实 全局范围(它可能有未知的副作用)
      • @Raynos,我阅读了这个问题,并且知道它在节点中。 window 关键字在那里是因为我首先在 jsfiddle 中对其进行了测试,而不是盲目地喷出代码并希望它有效。我很遗憾没有再次校对它。
      【解决方案9】:

      作用域是由函数创建的,作用域与函数保持一致,因此最接近您要求的是将函数从a() 传递到b(),并且该函数将继续具有从a() 访问作用域变量。

      function a(){
         var x = 5;
         var obj = {..};
         b(function() { /* this can access var x and var obj */ });
      }
      function b( fn ){
      
          fn(); // the function passed still has access to the variables from a()
      
      }
      

      虽然b() 无法直接访问函数所传递的变量,但如果传递的函数返回对象。

      function a(){
         var x = 5;
         var obj = {..};
         b(function() { x++; return obj; });
      }
      function b( fn ){
      
          var obj = fn();
          obj.some_prop = 'some value'; // This new property will be updated in the
                                        //    same obj referenced in a()
      
      }
      

      【讨论】:

      • @Erik:放手吧。这不是那么有趣,而且有点不同。
      • @patrick b 中变量 a 的访问权限在哪里? @gion 当然可以。 :)
      • @Erik:没有,除了函数允许操作的任何容量。 “虽然 b() 不能直接访问变量...”
      • @Erik:嗯,语言不支持问题的实际要求(直接访问),但它确实证明了间接访问是可能的,如a++所示。
      • 我指的是b内部的“//访问a或obj ...”。无论如何,我并不是要吹毛求疵,我只是想帮助您改进答案。
      【解决方案10】:

      如何使用bind

      function funcA(param) {     
          var bscoped = funcB.bind(this);     
          bscoped(param1,param2...)
      }
      

      【讨论】:

      • 如果 funcA 定义在全局范围内,通过 bind 传递的“this”将是窗口。 funcA 中定义的任何参数都不能在 funcB 中读取。或者我在这里错过了什么?不过,当传递 funcB.bind(this.funcA) 时,我只能访问定义为 funcA.variable 的变量。
      【解决方案11】:

      没有。

      您正在访问本地范围对象。 [[Context]]

      不能公开访问它。

      现在既然是 node.js,您应该能够编写一个 C++ 插件,让您可以访问 [[Context]] 对象。我强烈建议不要这样做,因为它为 JavaScript 语言带来了专有扩展。

      【讨论】:

      • 投反对票有什么理由吗?如果您可以访问[[Context]],请让我知道。
      • 刚刚给你投了赞成票。如果有人写这个扩展我很想知道,那么它不是专有的。让我大吃一惊的是,人们将其称为改变范围。您所做的只是更改对对象的引用并将其包含在函数的范围内。要真正改变真正的“范围”,你需要按照你在这里所说的去做,改变这些东西指向的框架。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-17
      • 2018-11-28
      • 2018-06-12
      • 2017-12-20
      相关资源
      最近更新 更多