我试图将函数范围传递给回调方法。我遇到的问题是我得到了对象范围,它不能让我访问原始函数中的参数和局部变量。我对“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();
这里的问题是传递给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
}
我需要有人来俱乐部我在这里头......路过的时候“这”在我的第一种情况,当然这是在全球范围内(我在一个全局定义的函数)...我的问题是,我在通过范围时我想到了我可以访问本地定义的变量和参数w /在那个上下文中......我是否摇摆了我之前对JS的理解?如何完成这项任务?
答案 0 :(得分: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
}
所以它与写作相同:
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, window);
}
之所以如此,是因为您全局定义了查找功能。在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();
在这种情况下,您发送匿名函数作为回调,它在查找函数中定义,因此它可以访问其局部变量;我的控制台在这个cae中显示了我:
myHandler(): bar: food
{"colors":["red","green"],"name":"Jones","what":"thang"}
为了更容易支持,您可以在查找函数中定义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
}
另一方面,为什么一个函数应该可以访问另一个函数的局部变量?也许它可以重新设计......
使代码正常工作的另一种方法是使用匿名函数,而不是查找(如果你只声明并执行一次该函数,它将起作用):
(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);
}
)();
结果相同,但不再有查找功能......
还有一个想法让它工作......实际上你需要在定义了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
}
关于JavaScript范围和结束的阅读资源很少:
答案 1 :(得分:2)
如果代码结构如此,则代码可以正常工作。
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
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + bar); // <- prob: bar undefined
console.log(JSON.stringify(data));
}
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
lookup();
myHandler函数可以访问查找的局部变量,因为它是一个闭包。
我可能会尝试通过构造这样的代码来实现相同的结果。
function myHandler(data, bar, ctx) {
console.log('myHandler(): bar: ' + bar); // <- prob: bar undefined
console.log(JSON.stringify(data));
}
MySvcWrap = {
doWork: function(p1, callback) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback(result);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler.bind(this, bar)); // callback function is bound to the scope
}
lookup();
我在查找方法中使用bind,而不是传递范围。使用bind我也可以添加我希望从该范围传递的局部变量。
当然,由于旧版浏览器中没有绑定,您需要通过框架添加它,或者使用添加该方法的许多小代码片段中的一个(如果不存在)。
答案 2 :(得分:0)
我的第一个答案有点快,并且Maxym在下面的评论中留下了一些间隙整体,感谢通知我:)这就是我在回去工作之前快速发布的内容: p 的
我在第一个答案中试图得到的是,如果你想使用绑定从函数lookup
访问函数myHandler
中的变量(这超出了lookup
的范围)你不得不使用var
而是使用this
。
使用var
只会使lookup's
私有作用域和嵌套在其中的任何函数都可以访问,这是其他答案所展示的(并且可能是最佳路径)
下面是一个更新的示例,说明如何将查找范围传递给myHandler,使myHandler完全脱离查找范围。希望这将有助于阐明:
“我遇到的问题是我得到了对象范围,它不能让我访问原始函数中的参数和局部变量。”
正如我之前回答this
的评论中所述,可能会变得棘手,如果不像我在第一个例子中那样小心,你最终可能会向global
范围添加内容。 :(所以我添加了一些hack'ish检查以查看范围this
确保它不是window
用于演示目的......
<强> Live Example 强>
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + this.bar); // <- must use `this`
console.log('myHandler(): privateBar: ' + this.privateBar); // <- undefined because it's privately scoped
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() {
if(this == window) return lookup.call(lookup); // <- my hack'ish check
var privateBar = 'private food'; // private local var
this.bar = 'food'; // public local var
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
lookup();
console.log('global space - bar: ' + this.bar);