Кстати, несколько слов об областях в вашем коде:
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:
- Объяснение объема и закрытий JavaScript
- Поднятие Javascript - закрытие и лексическая область видимости
- JavaScript: расширенные задачи и другие головоломки - очень хорошая презентация по теме