Конечно, есть много таких подходов, как синхронный запрос, обещание, но из моего опыта я думаю, что вы должны использовать подход обратного вызова. Естественно, что асинхронное поведение Javascript. Итак, ваш фрагмент кода можно переписать немного иначе:
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
myCallback(response);
}
});
return result;
}
function myCallback(response) {
// Does something.
}
Я понимаю их на примерах. :)
Во-первых, Лексическая область (также называемая Static Scope) в синтаксисе C-like:
void fun()
{
int x = 5;
void fun2()
{
printf("%d", x);
}
}
Каждый внутренний уровень может получить доступ к своим внешним уровням.
Существует другой способ, называемый Dynamic Scope, используемый первой реализацией Lisp, снова в C-подобном синтаксисе:
void fun()
{
printf("%d", x);
}
void dummy1()
{
int x = 5;
fun();
}
void dummy2()
{
int x = 10;
fun();
}
Здесь fun
может либо получить доступ к x
в dummy1
, либо dummy2
или любой x
в любой функции, вызывающей fun
с x
, объявленной в нем.
dummy1();
будет печатать 5,
dummy2();
будет печатать 10.
Первый называется static, поскольку он может быть выведен во время компиляции, второй называется динамическим, поскольку внешняя область является динамической и зависит от цепного вызова функций.
Я считаю, что статическое оглавление легче для глаза. Большинство языков пошло так, в конце концов, даже Lisp (можно сделать оба, правильно?). Динамическое масштабирование похоже на передачу ссылок на все переменные вызываемой функции.
Пример того, почему компилятор не может вывести внешнюю динамическую область функции, рассмотрим наш последний пример, если мы напишем что-то вроде этого:
if(/* some condition */)
dummy1();
else
dummy2();
Цепочка вызовов зависит от условия выполнения. Если это правда, то цепочка вызовов выглядит так:
dummy1 --> fun()
Если условие ложно:
dummy2 --> fun()
Внешняя область действия fun
в обоих случаях равна caller плюс вызывающий абонент и т. д. .
Просто отметим, что язык C не допускает вложенных функций и динамического охвата.
Лексическая область означает, что функция просматривает переменные в контексте, где она была определена, а не в области, непосредственно связанной с ней.
Посмотрите, как лексическая область работает в Lisp, если вы хотите более подробно. Выбранный ответ Кайла Кронина в Динамические и лексические переменные в Common Lisp намного яснее ответов здесь.
Кстати, я узнал об этом только в классе Lisp, и это также применимо и в JS.
Я запустил этот код в консоли хром.
// javascript equivalent Lisp
var x = 5; //(setf x 5)
console.debug(x); //(print x)
function print_x(){ //(defun print-x ()
console.debug(x); // (print x)
} //)
(function(){ //(let
var x = 10; // ((x 10))
console.debug(x); // (print x)
print_x(); // (print-x)
})(); //)
Выход :
5
10
5
Вот другой вопрос по этому вопросу, который мы можем получить, сделав шаг назад и рассмотрев роль обзора в более широких рамках интерпретации (запуск программы). Другими словами, представьте, что вы строили интерпретатор (или компилятор) для языка и отвечали за вычисление вывода, учитывая программу и некоторый ввод в нее.
Интерпретация включает в себя отслеживание трех вещей:
1) Состояние, а именно, переменные и ссылочные ячейки памяти в куче и стеке.
2) Операции над этим состоянием - а именно, каждая строка кода в вашей программе
3) Окружающая среда, в которой выполняется данная операция, а именно проекция состояния на операцию.
Интерпретатор запускается в первой строке кода в программе, вычисляет его среду, запускает строку в этой среде и фиксирует ее влияние на состояние программы. Затем он следует за потоком управления программой для выполнения следующей строки кода и повторяет процесс до завершения программы.
Способ вычисления среды для любой операции осуществляется через формальный набор правил, определяемых язык программирования. Термин «привязка» часто используется для описания отображения общего состояния программы на значение в среде. Обратите внимание, что под «общим состоянием» мы не имеем в виду глобальное состояние, а скорее сумму всех достижимых определений в любой момент выполнения)
. Это структура, в которой определена задача определения области видимости. Теперь к следующей части наших опций.
Это суть динамического охвата, в котором среда, в которой работает любой код, связана с состоянием программы, как определено ее выполнением context.
Другими словами, с помощью Lexical Scope среда, которую видит любой код, привязана к состоянию, связанной с областью, определенной явно на языке, например блоком или функция.
Лексическая (статическая) AKA-область относится к определению области переменной, основанной исключительно на ее позиции в текстовом корпусе кода. Переменная всегда относится к среде верхнего уровня. Полезно понять это в отношении к динамической области.
Давайте попробуем кратчайшее определение:
Лексическое определение определяет, как имена переменных разрешаются во вложенных функциях: внутренние функции содержат область родительских функций, даже если родительская функция вернулась.
Вот и все! Чтобы понять, что это значит, я написал подробное сообщение в блоге о области функций и лексическом охвате в JavaScript, который можно найти здесь здесь . Возможно, это может случиться и с кем-то другим.
Лексическая область в Javascript означает, что переменная, определенная вне функции, может быть доступна внутри другой функции, определенной после объявления переменной. Но противоположное неверно, переменные, определенные внутри функции, не будут доступны вне этой функции.
Это понятие сильно используется в закрытии в Javascript.
Скажем, у нас есть ниже кода.
var x = 2;
var add = function() {
var y = 1;
return x + y;
};
Теперь, когда вы вызываете add () ->, это будет печатать 3.
Таким образом, функция add () обращается к глобальной переменной x, которая является определенный перед функцией функции add. Это вызвано из-за лексического охвата в javascript.
var scope = "I am global";
function whatismyscope(){
var scope = "I am just a local";
function func() {return scope;}
return func;
}
whatismyscope()()
Вышеприведенный код вернет «Я просто локальный». Он не вернется «Я глобальный». Поскольку функция func () подсчитывает, где была изначально определена, которая находится в рамках функции whatismyscope.
Она не будет беспокоиться о том, что она называется (глобальная область / изнутри другой функции) поэтому глобальное значение области I глобально не будет напечатано.
Это называется лексическим охватом, где « функции выполняются с использованием цепочки областей действия, которая действовала, когда они были определены " - согласно Руководству по определению JavaScript.
Лексический охват - очень очень мощная концепция.
Надеюсь, это поможет ..:)
IBM определяет его как:
Часть программы или сегмента, в которой применяется декларация. Идентификатор, объявленный в подпрограмме, известен внутри этой процедуры и внутри всех вложенных подпрограмм. Если вложенная подпрограмма объявляет элемент с тем же именем, внешний элемент недоступен во вложенной подпрограмме.
blockquote>Пример 1:
function x() { /* Variable 'a' is only available to function 'x' and function 'y'. In other words the area defined by 'x' is the lexical scope of variable 'a' */ var a = "I am a"; function y() { console.log( a ) } y(); } // outputs 'I am a' x();
Пример 2:
function x() { var a = "I am a"; function y() { /* If a nested routine declares an item with the same name, the outer item is not available in the nested routine. */ var a = 'I am inner a'; console.log( a ) } y(); } // outputs 'I am inner a' x();
Мне нравятся полнофункциональные, языковые агностические ответы от таких людей, как @Arak. Поскольку этот вопрос был помечен JavaScript , хотя я хотел бы отметить некоторые примечания, очень специфичные для этого языка.
В javascript наши выборки для определения области видимости:
var _this = this; function callback(){ console.log(_this); }
callback.bind(this)
Стоит отметить, Я думаю, что JavaScript на самом деле не имеет динамического охвата . .bind
настраивает ключевое слово this
, и это близко, но технически не то же самое.
Вот пример, демонстрирующий оба подхода. Вы делаете это каждый раз, когда принимаете решение о том, как обрабатывать обратные вызовы, чтобы это применимо к обещаниям, обработчикам событий и т. Д.
что вы могли бы назвать Lexical Scoping
обратных вызовов в JavaScript:
var downloadManager = {
initialize: function() {
var _this = this; // Set up `_this` for lexical access
$('.downloadLink').on('click', function () {
_this.startDownload();
});
},
startDownload: function(){
this.thinking = true;
// request the file from the server and bind more callbacks for when it returns success or failure
}
//...
};
Другой способ охвата - использовать Function.prototype.bind
:
var downloadManager = {
initialize: function() {
$('.downloadLink').on('click', function () {
this.startDownload();
}.bind(this)); // create a function object bound to `this`
}
//...
Эти методы, насколько мне известно, поведенчески эквивалентны.
Лексическое определение: переменные, объявленные вне функции, являются глобальными переменными и отображаются везде в программе JavaScript. Переменные, объявленные внутри функции, имеют область действия и видны только для кода, который появляется внутри этой функции.