将范围传递给回调函数/绑定

Mer*_*erl 16 javascript closures scope

我试图将函数范围传递给回调方法.我遇到的问题是我得到了对象范围,它不能让我访问原始函数中的参数和局部变量.除了本地声明的变量和参数之外,我对"this"的理解意味着当前上下文(无论是窗口还是某个对象).[引用Richard Cornford在http://jibbering.com/faq/notes/closures/关于"执行上下文"部分的出色工作].我也理解JavaScript中的变量具有函数作用域(如果它们在函数内声明,则只能从该函数中访问它们).

有了这样的理解,在一个新的环境中,我试图编写一个模式,我为我以前的雇主做了很多,调用异步方法,指定一个回调处理程序并传递我的当前范围,期望它在回调方法中可用.我不认为在我目前的环境中就是这种情况.(披露:我在以前的环境中使用ExtJS ......让我觉得现在我觉得我对框架有点过于惬意,对正在发生的事情作出假设).

我的简单测试代码演示了我正在尝试做什么和什么不起作用.

function myHandler(data, ctx) {
    console.log('myHandler():  bar: ' + bar);  // <- prob: bar undefined 
    console.log(JSON.stringify(data));
}
MySvcWrap = {
    doWork: function(p1, callback, scope) {
        var result = {colors: ['red', 'green'], name:'Jones', what: p1};
        if (callback) {
            callback.call(scope||this,result, scope);
        } 
    }
}
function lookup() {
    var bar = 'food'; // local var
    MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}

lookup();
Run Code Online (Sandbox Code Playgroud)

这里的问题是传递给MySvcWrap.doWork的'this'在这种情况下是Window全局对象.我的目的是将函数的执行上下文传递给myHandler.

我试过了什么 如果,而不是'this',我传递一个对象,这是有效的,例如:

function myHandler(data, ctx) {
    console.log('myHandler():  this.bar: ' + this.bar);  // <- no prob: this.bar 
    console.log(JSON.stringify(data));
}

function lookup() {
    var bar = 'food'; // local var
    MySvcWrap.doWork('thang', myHandler, {bar: bar}); // scope object is just object
}
Run Code Online (Sandbox Code Playgroud)

我需要有人在这里嘲笑我...当我在第一个案例中传递'this'时,当然这是全局范围(我在一个全局定义的函数中)...我的问题是我在通过时想到的在这种情况下我可以访问本地定义的变量和参数的范围......我是否摇摆了我之前对JS的理解?如何完成这项任务?

Max*_*xym 16

顺便说一句,关于代码中范围的几句话:

function lookup() {
    var bar = 'food'; // local var
    MySvcWrap.doWork('thang', myHandler, this); // this here points to window object and not to the function scope
}
Run Code Online (Sandbox Code Playgroud)

所以它与写作相同:

function lookup() {
    var bar = 'food'; // local var
    MySvcWrap.doWork('thang', myHandler, window); 
}
Run Code Online (Sandbox Code Playgroud)

这是因为你全局定义查找功能.内部doWork函数,当你写this它指向MySvcWrap对象时(因为该函数是在该对象内定义的).

如果您的回调函数必须看到bar变量,那么它应该在相同的范围内定义,就像那样

MySvcWrap = {
    doWork: function(p1, callback, scope) {
        var result = {colors: ['red', 'green'], name:'Jones', what: p1};
        if (callback) {
            callback.call(scope||this,result, scope);
        } 
    }
}
function lookup() {
    var bar = 'food'; // local var
    MySvcWrap.doWork('thang', 
        function (data, ctx) {
            console.log('myHandler():  bar: ' + bar); 
            console.log(JSON.stringify(data));
        }, 
        this); // scope object is this
}

lookup();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您发送匿名函数作为回调,它在查找函数内定义,因此它可以访问其局部变量; 我的控制台在这个cae中显示我:

myHandler(): bar: food
{"colors":["red","green"],"name":"Jones","what":"thang"}
Run Code Online (Sandbox Code Playgroud)

为了使其更容易支持,您可以在查找函数中定义myHandler:

function lookup() {
    var bar = 'food'; // local var
    var myHandler = function(data, ctx) {
        console.log('myHandler():  bar: ' + bar);
        console.log(JSON.stringify(data));
    };
    MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
Run Code Online (Sandbox Code Playgroud)

另一方面,为什么一个函数应该可以访问另一个函数的局部变量?也许它可以重新设计......

使代码工作的另一种方法是使用匿名函数,而不是查找(如果你只声明并执行一次该函数,它将起作用):

(function() {
   var bar = 'food';

   function myHandler(data, ctx) {
       console.log('myHandler():  bar: ' + bar);  
       console.log(JSON.stringify(data));
    } 
    MySvcWrap = {
       doWork: function(p1, callback, scope) {
           var result = {colors: ['red', 'green'], name:'Jones', what: p1};
           if (callback) {
               callback.call(scope||this,result, scope);
           } 
       }
    }
    MySvcWrap.doWork('thang', myHandler, this);
  }
)();
Run Code Online (Sandbox Code Playgroud)

结果是一样的,但不再有查找功能......

还有一个想法让它工作......实际上你需要在定义了bar变量的同一范围内定义回调处理程序,所以它可以做得有点棘手,但也可以替代:

function myHandler(bar) { // actually in this case better to call it createHandler 
    return function(data, ctx) {
        console.log('myHandler():  bar: ' + bar); 
        console.log(JSON.stringify(data));
    } 
}
MySvcWrap = {
    doWork: function(p1, callback, scope) {
        var result = {colors: ['red', 'green'], name:'Jones', what: p1};
        if (callback) {
            callback.call(scope||this,result, scope);
        } 
    }
}
function lookup() {
    var bar = 'food'; // local var
    MySvcWrap.doWork('thang', myHandler(bar), this); // scope object is this
}
Run Code Online (Sandbox Code Playgroud)

关于JavaScript范围和结束的阅读资源很少:

  1. 解释JavaScript范围和闭包
  2. 拾起Javascript - 闭包和词法范围
  3. JavaScript:高级范围和其他难题 - 关于主题的非常好的演示