Я использую XMLHttpRequest, и я хочу получить доступ к локальной переменной в функции обратного вызова успеха.
Вот код:
function getFileContents(filePath, callbackFn) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callbackFn(xhr.responseText);
}
}
xhr.open("GET", chrome.extension.getURL(filePath), true);
xhr.send();
}
И я хочу назвать его как это:
var test = "lol";
getFileContents("hello.js", function(data) {
alert(test);
});
Здесь, test
был бы вне объема функции обратного вызова, так как только переменные функции включения доступны в функции обратного вызова. Что состоит в том, чтобы передать лучший способ test
к функции обратного вызова так alert(test);
отобразится test
правильно?
Править:
Теперь, если у меня есть следующий код, называя функцию, определяемую выше:
for (var test in testers) {
getFileContents("hello.js", function(data) {
alert(test);
});
}
alert(test);
кодируйте только печатает последнее значение test
от for
цикл. Как я делаю его так, чтобы это распечатало значение test
в течение времени, в который функция getFileContents
был назван? (Я хотел бы сделать это без изменения getFileContents
потому что это - очень общая функция помощника, и я не хочу делать это конкретным путем передачи определенной переменной как test
к нему.
С предоставленным вами кодом тест
по-прежнему будет в области действия обратного вызова. xhr
не будет, кроме xhr.responseText
, переданного как данные
.
Обновлено из комментария :
Предполагая, что ваш код выглядит примерно так:
for (var test in testers)
getFileContents("hello"+test+".js", function(data) {
alert(test);
});
}
При запуске этого скрипта test
будет присвоено значение ключей в тестерах
- getFileContents
вызывается каждый раз, что запускает запрос в фоновом режиме. По завершении запроса он вызывает обратный вызов. тест
будет содержать ОКОНЧАТЕЛЬНОЕ ЗНАЧЕНИЕ из цикла, поскольку этот цикл уже завершил выполнение.
Есть метод, который вы можете использовать, называемый закрытием, который решит такую проблему. Вы можете создать функцию, которая возвращает вашу функцию обратного вызова, создав новую область видимости, которую вы можете удерживать для своих переменных с помощью:
for (var test in testers) {
getFileContents("hello"+test+".js",
(function(test) { // lets create a function who has a single argument "test"
// inside this function test will refer to the functions argument
return function(data) {
// test still refers to the closure functions argument
alert(test);
};
})(test) // immediately call the closure with the current value of test
);
}
Это в основном создаст новую область видимости (вместе с нашей новой функцией), которая будет «удерживать» значение тест
.
Другой способ записать то же самое:
for (var test in testers) {
(function(test) { // lets create a function who has a single argument "test"
// inside this function test will refer to the functions argument
// not the var test from the loop above
getFileContents("hello"+test+".js", function(data) {
// test still refers to the closure functions argument
alert(test);
});
})(test); // immediately call the closure with the value of `test` from `testers`
}
В этом сценарии test будет разрешен, как вы и ожидали, но значение this
может быть другим. Обычно, чтобы сохранить область видимости, вы делаете его параметром асинхронной функции, как например:
function getFileContents(filePath, callbackFn, scope) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callbackFn.call(scope, xhr.responseText);
}
}
xhr.open("GET", chrome.extension.getURL(filePath), true);
xhr.send();
}
//then to call it:
var test = "lol";
getFileContents("hello.js", function(data) {
alert(test);
}, this);
JavaScript использует лексическую область видимости , что в основном означает, что ваш второй пример кода будет работать так, как вы предполагаете.
Рассмотрим следующий пример, заимствованный из Definitive Guide Дэвида Фланагана 1 :
var x = "global";
function f() {
var x = "local";
function g() { alert(x); }
g();
}
f(); // Calling this function displays "local"
Также имейте в виду, что в отличие от C, C ++ и Java, JavaScript не имеет области видимости на уровне блоков.
Кроме того, вам может быть интересно ознакомиться со следующей статьей, которую я настоятельно рекомендую:
1 Дэвид Фланаган: JavaScript - Окончательный Руководство , четвертое издание, стр. 48.