Что такое лексический объем?

может кто-нибудь, пожалуйста, дать мне краткое введение в лексический охват?

12 ответов


я понимаю их на примерах. :)

во-первых, лексическая область (также называемая статической областью), в C-подобном синтаксисе:

void fun()
{
    int x = 5;

    void fun2()
    {
        printf("%d", x);
    }
}

каждый внутренний уровень может получить доступ к своим внешним уровням.

существует другой способ, называемый динамической областью, используемой первой реализацией Lisp, снова в синтаксисе C-like:

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-динамического обзора не получил большого внимания, и внимание, которое он получил, означает, что ему, вероятно, нужно немного больше (это не критика других ответов, а скорее "о, этот ответ заставил нас пожелать, чтобы было немного больше"). Итак, вот еще немного:

динамическая область видимости означает, что переменная доступна для большая программа в течение срока службы вызова функции-или во время выполнения функции. Действительно, Википедия На самом деле делает хорошую работу с объяснение между двумя. Чтобы не запутать его, вот текст, описывающий динамическую область обзора:

...[I]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, которая определена до добавления функции метода. Это называется из-за лексической области в javascript.


вот другой угол по этому вопросу, который мы можем получить, сделав шаг назад и посмотрев на роль области охвата в более широких рамках интерпретации (запуск программы). Другими словами, представьте, что вы создаете интерпретатор (или компилятор) для языка и отвечаете за вычисление вывода, учитывая программу и некоторый вход в нее.

интерпретация включает в себя отслеживание трех вещей:

1) государство - а именно, переменные и ссылки ячейки памяти в куче и стеке.

2) операции над этим состоянием-а именно, каждая строка кода в вашей программе

3) среда, в которой выполняется данная операция, а именно проекция состояния на операцию.

интерпретатор начинает с первой строки кода в программе, вычисляет ее среду, запускает строку в этой среде и фиксирует ее влияние на состояние программы. Затем он следует за потоком управления программы для выполнения следующая строка кода, и повторяет процесс до конца программы.

способ вычисления среды для любой операции заключается в формальном наборе правил, определяемых языком программирования. Термин "привязка" часто используется для описания сопоставления общего состояния программы со значением в среде. Обратите внимание, что под "общим состоянием" мы подразумеваем не глобальное состояние, а сумму всех достижимых определений в любой точке исполнение)

Это структура, в которой определяется проблема области видимости. Теперь к следующей части, каковы наши варианты.

  • как разработчик интерпретатора, вы можете упростить свою задачу, сделав среду как можно ближе к состоянию программы. Соответственно, среда строки кода будет просто определяться средой предыдущей строки кода с последствиями этой операции, применяемой к ней, независимо от того, предыдущая строка была назначением, вызовом функции, возвращением из функции или структурой управления, такой как цикл while.

суть динамическое определение области, в котором среда, в которой выполняется любой код, привязана к состоянию программы, определенному контекстом ее выполнения.

  • или, вы можете подумать о программисте, использующем ваш язык, и упростить его задачу отслеживания значений переменной брать. Существует слишком много путей и слишком много сложностей, связанных с рассуждениями о результате всего прошлого исполнения. Лексической Области Видимости помогает сделать это, ограничивая текущую среду частью состояния определена в текущий блок, функция или другая единица области и ее родитель (т. е. блок, заключающий текущие часы или функцию, которая вызвала настоящую функцию).

другими словами, с лексико Объем среда, которую видит любой код, связана с состоянием, связанным с областью, явно определенной на языке, такой как блок или функция.