JavaScript передает область действия другой функции - PullRequest
29 голосов
/ 14 июня 2011

Можно ли как-то передать область действия функции другому?

Например,

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

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

Я бы предпочел получить прямой доступ к переменным, т. Е. Не использовать ничего подобного this.a или this.obj, но просто используйте x или obj напрямую.

Ответы [ 11 ]

27 голосов
/ 14 июня 2011

Единственный способ по-настоящему получить доступ к закрытой области видимости функции a - это объявить b внутри a, чтобы он образовал замыкание, обеспечивающее неявный доступ к переменным a.

Вот несколько вариантов для вас.

Прямой доступ

  1. Объявите b внутри a.

    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();
    

Это единственный способ использовать переменные a непосредственно в b без дополнительного кода для перемещения.Если вас устраивает небольшая «помощь» и / или косвенное обращение, вот еще несколько идей.

Косвенный доступ

  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 объект с геттерами и сеттерами, которые могут обращаться к приватным переменным 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();
    

    Методы получения и установки могут быть открытыми и назначаться объекту this из a, но таким образом они доступны только в том случае, если они явно переданы из 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();
    
8 голосов
/ 14 июня 2011

Область создается функциями, а область остается с функцией, поэтому наиболее близким к тому, что вы просите, будет передать функцию из 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()

}
6 голосов
/ 15 июня 2011

как насчет использования bind

function funcA(param) {     
    var bscoped = funcB.bind(this);     
    bscoped(param1,param2...)
}
6 голосов
/ 14 июня 2011

номер

Вы получаете доступ к объекту локальной области. [[Context]].

Вы не можете публично получить к нему доступ.

Теперь, поскольку это node.js, вы сможете написать плагин C ++, который дает вам доступ к объекту [[Context]]. Я настоятельно рекомендую против этого, так как он привносит проприетарные расширения в язык JavaScript.

2 голосов
/ 14 июня 2011

Я думаю, что самое простое, что вы можете сделать - это передать переменные из одной области видимости в функцию вне этой области.Если вы переходите по ссылке (например, Объекты), 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
}
2 голосов
/ 14 июня 2011

Как уже говорили другие, вы не можете пройти такой объем.Тем не менее, вы можете правильно охватывать переменные, используя самостоятельно выполняемые анонимные функции (или сразу выполняемые, если вы педантичны):

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

a();
2 голосов
/ 14 июня 2011

Вы не можете "передать область" ... не то, что я знаю.
Вы можете передать объект, на который ссылается функция, используя apply или call и отправить текущий объект (this) в качестве первого параметра вместо простого вызова функции:

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

Единственный способ для функции получить доступ к определенной области - это объявить в этой области.
Kind'a хитрый.
Это привело бы к чему-то вроде:

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

Но это как бы победило цель.

0 голосов
/ 14 июня 2011

Вы пробовали что-то вроде этого:

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
   }
}
0 голосов
/ 14 июня 2011
function a(){
   var x = 5;
   var obj = {..};
   var b = function()
   {
        document.println(x);
   }
   b.call();
}
0 голосов
/ 14 июня 2011
function a(){
   this.x = 5;
   this.obj = {..};
   var self = this;
   b(self);
}
function b(scope){
   //access x or obj....

}
...