Что такое лексический объем?
может кто-нибудь, пожалуйста, дать мне краткое введение в лексическую область?
12 ответов:
я понимаю их на примерах. :)
во-первых, лексическая область (также называемая статической областью), в C-подобном синтаксисе:
void fun() { int x = 5; void fun2() { printf("%d", x); } }
каждый внутренний уровень может получить доступ к своим внешним уровням.
есть еще один способ, называемый динамической областью, используемой первой реализацией 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.
первый называется статическим, потому что он может быть выведен во время компиляции, второй называется динамическим, потому что внешняя область является динамической и зависит от цепного вызова функций.
я считаю, что статическое сканирование легче для глаз. Большинство языков пошли по этому пути в конечном итоге даже Lisp(может сделать и то, и другое, верно?). Динамическое определение области похоже на передачу ссылок всех переменные для вызываемой функции.
пример того, почему компилятор не может вывести внешнюю динамическую область функции, рассмотрим наш последний пример, если мы напишем что-то вроде этого:
if(/* some condition */) dummy1(); else dummy2();
цепочка вызовов зависит от условия времени выполнения. Если это правда, то цепочка вызовов выглядит так:
dummy1 --> fun()
, если условие ложно:
dummy2 --> fun()
внешний объем
fun
в обоих случаях звонивший плюс вызывающий звонящий и так далее.просто чтобы упомянуть, что язык C не позволяет вложенные функции или динамическое определение области.
давайте попробуем самое короткое определение:
Лексической Области Видимости определяет, как имена переменных разрешаются во вложенных функциях:внутренние функции содержат область родительских функций, даже если родительская функция вернула.
вот и все! Чтобы помочь себе понять, что это значит, я написал подробное сообщение в блоге о объем функции и лексический объем в JavaScript, который можно найти здесь. Может быть, это послужит кому-то еще.
область определяет область, в которой доступны функции, переменные и т. д. Доступность переменной, например, определяется в ее контексте, скажем, функция, файл или объект, в котором они определены. Мы обычно называем эти локальные переменные.
лексическую часть означает, что вы можете получить от чтения исходного кода.
лексическая область также известна как статическая область.
динамическая область видимости определяет глобальные переменные, которые могут быть вызывается или ссылается из любого места после определения. Иногда они называются глобальными переменными, хотя глобальные переменные в большинстве языков программирования имеют лексическую область. Это означает, что он может быть получен из чтения кода, что переменная доступна в этом контексте. Возможно, нужно следовать предложению uses или includes, чтобы найти установку или определение, но код/компилятор знает о переменной в этом месте.
в динамической области, напротив, вы ищете в сначала локальная функция, затем поиск в функции, которая вызвала локальную функцию, затем поиск в функции, которая вызвала эту функцию, и так далее, вверх по стеку вызовов. "Динамический" относится к изменению, поскольку стек вызовов может быть разным каждый раз, когда вызывается данная функция, и поэтому функция может поражать разные переменные в зависимости от того, откуда она вызывается. (см. здесь)
чтобы увидеть интересный пример для динамической области см. здесь.
для получения дополнительной информации см. здесь и здесь.
некоторые примеры в Delphi / Object Pascal
Delphi имеет лексическую область.
unit Main; uses aUnit; // makes available all variables in interface section of aUnit interface var aGlobal: string; // global in the scope of all units that use Main; type TmyClass = class strict private aPrivateVar: Integer; // only known by objects of this class type // lexical: within class definition, // reserved word private public aPublicVar: double; // known to everyboday that has access to a // object of this class type end; implementation var aLocalGlobal: string; // known to all functions following // the definition in this unit end.
наиболее близким Delphi к динамической области является пара функций RegisterClass()/GetClass (). Для его использования см. здесь.
предположим, что время RegisterClass ([TmyClass]) вызывается для регистрации определенного класса невозможно предсказать, прочитав код (он вызывается в методе нажатия кнопки, вызываемом пользователем), код, вызывающий GetClass ('TmyClass'), получит результат или нет. Вызов RegisterClass () не обязательно должен находиться в лексической области единицы, использующей GetClass ();
еще одна возможность для динамической области являются анонимные методы (замыкания) в Delphi 2009, так как они знают переменные своей вызывающей функции. Он не следует по пути вызова оттуда рекурсивно и поэтому не является полностью динамической.
лексическая (ака статическая) область видимости относится к определению области видимости переменной, основанной исключительно на ее положении в текстовом корпусе кода. Переменная всегда ссылается на свою среду верхнего уровня. Это хорошо, чтобы понять это в отношение к динамической области.
var scope = "I am global"; function whatismyscope(){ var scope = "I am just a local"; function func() {return scope;} return func; } whatismyscope()()
приведенный выше код вернет "я просто местный". Он не вернется "я глобальный". Потому что функция func () подсчитывает, где изначально было определено, что находится в области действия функции whatismyscope.
Он не будет беспокоить от того, что он вызывается(глобальная область/даже из другой функции), поэтому значение глобальной области I am global не будет напечатано.
это называется лексической областью, где"функции выполняются используя цепочку областей, которая действовала, когда они были определены " - согласно Руководству по определению JavaScript.
лексический объем является очень мощным понятием.
надеюсь, что это помогает..:)
мне нравятся полнофункциональные, языковые агностические ответы от таких людей, как @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. Переменные, объявленные внутри функции, имеют область действия функции и видны только коду, который появляется внутри этой функции.
IBM определено как:
часть программы или сегментный блок, в котором объявление применяется. Идентификатор, объявленный в подпрограмме, известен в пределах этого рутина и во всех вложенных подпрограммах. Если вложенная процедура объявляет элемент с тем же именем, внешний элемент не доступен в вложенная процедура.
Пример 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();
существует важная часть разговора, связанная с лексическим и динамическим охватом, которая отсутствует: простое объяснение продолжительность жизни переменной области видимости-или , когда переменная может быть доступна.
динамическое определение только очень слабо соответствует "глобальному" определению в том смысле, как мы традиционно думаем об этом (причина, по которой я поднимаю сравнение между ними, заключается в том, что оно уже было указано - а я нет особенно нравится связан объяснение статьи); вероятно, лучше всего мы не делаем сравнение между глобальным и динамическим - хотя предположительно, согласно связанной статье,"...[он] полезен в качестве замены переменных глобального масштаба."
Итак, на простом английском языке, в чем важное различие между двумя механизмами определения области?
лексическая область была определена очень хорошо во всех ответах выше: лексически ограниченные переменные доступный-или доступный-на локальном уровне функции, в которой он был определен.
однако-поскольку это не фокус OP-динамического обзора, он не получил большого внимания, и внимание, которое он получил, означает, что ему, вероятно, нужно немного больше (это не критика других ответов, а скорее "о, этот ответ заставил нас пожелать, чтобы было немного больше"). Итак, вот еще немного:
динамическая область означает, что переменная доступна для большая программа во время жизни вызова функции - или, в то время как функция выполняется. Действительно, Википедия На самом деле делает хорошую работу с объяснение между двумя. Чтобы не запутать его, вот текст, который описывает динамическое определение области:
...[Я]n динамическое определение области (или динамический прицел), если объем имени переменной является определенная функция, тогда ее область действия-это период времени, в течение которого функция выполняется: в то время как функция работает, переменная имя существует и привязано к его переменной, но после функции возвращает имя переменной не существует.
лексическая область означает, что функция ищет переменные в контексте, где она была определена, а не в области непосредственно вокруг нее.
посмотрите, как работает лексическая область в Lisp, если вы хотите более подробно. Выбранный ответ Кайла Кронина в динамические и лексические переменные в Common Lisp намного яснее, чем ответы здесь.
по совпадению я узнал об этом только в классе Lisp, и это происходит в JS как что ж.
Я запустил этот код в консоли chrome.
// 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
лексическая область в Javascript означает, что переменная, определенная вне функции, может быть доступна внутри другой функции, определенной после объявления переменной. Но обратное неверно, переменные, определенные внутри функции, не будут доступны вне этой функции.
эта концепция широко используется в замыканиях в Javascript.
Допустим у нас есть ниже код.
var x = 2; var add = function() { var y = 1; return x + y; };
теперь, когда вы вызываете add () -- > это будет печатать 3.
Итак, функция add () обращается к глобальной переменной x, которая определена перед функцией метода add. Это называется из-за лексической области в javascript.
вот другой угол по этому вопросу, который мы можем получить, сделав шаг назад и посмотрев на роль определения области в более широких рамках интерпретации (запуск программы). Другими словами, представьте, что вы создаете интерпретатор (или компилятор) для языка и отвечаете за вычисление выходных данных, учитывая программу и некоторый вход в нее.
интерпретация включает в себя отслеживание трех вещей:
1) государство - а именно, переменные и ссылки ячейки памяти в куче и стеке.
2) операции над этим состоянием-а именно, каждая строка кода в вашей программе
3) среда, в которой выполняется данная операция, а именно - проекция состояния на операцию.
интерпретатор начинается с первой строки кода в программе, вычисляет ее окружение, запускает строку в этой среде и фиксирует ее влияние на состояние программы. Затем он следует за потоком управления программы для выполнения следующая строка кода, и повторяет процесс до конца программы.
способ вычисления среды для любой операции осуществляется с помощью формального набора правил, определенных языком программирования. Термин "привязка" часто используется для описания отображения общего состояния программы на значение в среде. Обратите внимание, что под "общим состоянием" мы подразумеваем не глобальное состояние, а сумму всех достижимых определений в любой точке мира. исполнение)
Это структура, в которой определяется проблема определения области. Теперь перейдем к следующей части наших вариантов.
- как исполнитель интерпретатора, вы можете упростить свою задачу, сделав среду как можно ближе к состоянию программы. Соответственно, окружение строки кода будет просто определяться окружением предыдущей строки кода с последствиями этой операции, примененной к ней, независимо от того, является ли предыдущая строка была назначением, вызовом функции, возвращением из функции или структурой управления, такой как цикл while.
суть динамическое определение области, где среда, в которой выполняется любой код, привязана к состоянию программы, определенному контекстом ее выполнения.
- или, вы могли бы подумать о программисте, использующем ваш язык, и упростить его задачу отслеживания значений, которые может иметь переменная брать. Существует слишком много путей и слишком много сложностей, связанных с рассуждением о результате всего прошлого исполнения. Лексической Области Видимости помогает сделать это, ограничивая текущую среду частью состояния определена в текущий блок, функция или другая единица области видимости и ее родитель (т. е. блок, содержащий текущие часы, или функция, которая вызвала настоящую функцию).
другими словами, с лексико Объем среда, которую видит любой код, привязана к состоянию, связанному с областью, определенной явно в языке, например блоком или функцией.