Вопрос по javascript – Что такое лексический охват?

580

Может ли кто-нибудь дать мне краткое введение в лексическую сферу?

Возможно, спрашивающий не (или не очень) свободно говорил по-английски при написании этого вопроса Martin
Я думаю, что подобные вопросы - это здорово, потому что они создают контент для SO. ИМО, кого это волнует, если у вопроса нет усилий ... ответы будут отличным содержанием, и вот что важно на этой доске объявлений. Jwan622
В подкасте 58 Джоэл поощряет подобные вопросы, поскольку он хочет, чтобы ТАК стал местом для ответов, даже если на них были даны ответы в других местах. Это правильный вопрос, хотя можно сказать, что он немного вежливее. Ralph M. Rickenbach
@ rahul Я понимаю, что это старый вопрос. Но я уверен, что даже в 2009 году ТАК ожидал, что спрашивающ некоторые основные усилия к решению этого. Как оно есть, это не показываетлюбо усилия на всех. Может быть, поэтому за это проголосовали многие? P.P.
Вопрос вежливый, он просто говорит, что хочет. Вы можете ответить. Здесь не нужна чрезмерная политичность. Markus Siebeneicher

Ваш Ответ

13   ответов
605

First, Lexical Scope (также называемый Static Scope), в C-подобном синтаксисе:

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.

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

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

Пример того, почему компилятор не может определить внешнюю динамическую область видимости функции, рассмотрим наш последний пример, если мы напишем что-то вроде этого:

if(/* some condition */)
    dummy1();
else
    dummy2();

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

dummy1 --> fun()

Если условие ложно:

dummy2 --> fun()

Внешняя сфераfun в обоих случаях звонящий плюс вызывающий абонент и т. д..

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

Я также хотел бы отметить очень простой для понимания урок, который я только что нашел. Пример Арака хорош, но может быть слишком коротким для того, кому нужно больше примеров (на самом деле, по сравнению с другими языками ..). Посмотри. Важно пониматьэт, поскольку это ключевое слово приведет нас к пониманию лексической области. Howtonode.org / что-это-это CppLearner
Хорошо отметить, что у gcc есть расширение, позволяющее использовать вложенные функции. Corey Richardson
Это хороший ответ. Но вопрос помечен какJavaScript. Поэтому я думаю, что это не должно быть отмечено как принятый ответ. Лексическая сфера конкретно в JS отличается Boyang
Очень хороший ответ. Спасибо. @Boyang Я не согласен. Я не кодировщик Lisp, но нашел пример Lisp полезным, так как это пример динамической области видимости, который вы не получите в JS. dudewad
Первоначально я думал, что пример является допустимым кодом C и был сбит с толку, было ли в C. динамическая область видимости. Возможно, отказ от ответственности в конце можно перенести на перед примером кода? Yangshun Tay
225

Lexical Scoping определяет, как имена переменных разрешаются во вложенных функциях:ункции @inner содержат область действия родительских функций, даже если родительская функция вернула.

Вот и все!

Последняя часть: «даже если родительская функция вернулась» называется Closure. Juanma Menendez
40
var scope = "I am global";
function whatismyscope(){
   var scope = "I am just a local";
   function func() {return scope;}
   return func;
}

whatismyscope()()

«Я глобальный». Потому что функция func () считает, где изначально было определено, что находится в области действия whatismyscope.

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

Это называется лексическим ограничением, где " функции выполняются с использованием цепочки областей действия, которая действовала, когда они были определены "- в соответствии с Руководством по определению JavaScript.

Лексическая сфера - очень очень мощная концепция.

Надеюсь это поможет..:

38

в которой доступны функции, переменные и тому подобное. Доступность переменной, например, определяется в ее контексте, скажем, в функции, файле или объекте, в котором они определены. Мы обычно называем эти локальные переменные.

Лексическая часть означает, что вы можете извлечь область из чтения исходного кода.

Лексическая область также известна как статическая область.

Dynamic scope определяет глобальные переменные, которые могут быть вызваны или на которые можно ссылаться откуда угодно после их определения. Иногда их называют глобальными переменными, хотя глобальные переменные в большинстве языков программирования имеют лексическую область. Это означает, что из чтения кода можно получить информацию о том, что переменная доступна в этом контексте. Возможно, нужно найти условие использования или включения, чтобы найти указание или определение, но код / компилятор знает о переменной в этом месте.

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

Чтобы увидеть интересный пример динамического объема см.Во.

Подробнее см.Во а такжеВо.

Некоторые примеры в 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, поскольку они знают переменные своей вызывающей функции. Он не следует рекурсивному пути вызова и поэтому не является полностью динамическим.

+ 1 для простого языка (в отличие от сложного языка и примеров без особого описания) Pops
На самом деле private доступен во всем модуле, где определен класс. Вот почему «Строгий приват» был представлен в D2006. Marco van de Voort
Спасибо, Марко. Исправлено Ralph M. Rickenbach
36

основанной исключительно на ее положении в текстовом корпусе кода. Переменная всегда относится к ее среде верхнего уровня. Это хорошо понимать в отношение к динамическому объему.

31

независимые от языка ответы от таких людей, как @Arak. Поскольку этот вопрос был помечен JavaScript хотя я бы хотел добавить некоторые заметки, специфичные для этого языка.

В javascript мы можем выбрать следующие варианты:

как есть (без регулировки объема)lexicalvar _this = this; function callback(){ console.log(_this); }boundcallback.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
  }
  //...
};
Bound

Другой способ - использоватьFunction.prototype.bind:

var downloadManager = {
  initialize: function() {
    $('.downloadLink').on('click', function () {
      this.startDownload();
    }.bind(this)); // create a function object bound to `this`
  }
//...

Насколько мне известно, эти методы поведенчески эквивалентны.

11

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

12

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();
4

нге: простое объяснениепродолжительность жизн переменной области видимости - иликогд переменная может быть доступна.

Динамическое определение объема только очень слабо соответствует «глобальному» определению в том смысле, в котором мы традиционно думаем об этом (причина, по которой я привожу сравнение между ними, заключается в том, что оно уже было Упомянутый - и мне не очень нравится Связаны объяснение статьи); вероятно, лучше всего не проводить сравнение между глобальным и динамическим, хотя, согласно предположительной статье, «... [это] полезно в качестве замены глобально изменяемых переменных».

Итак, на простом английском, в чем заключается важное различие между двумя механизмами определения объема?

Лексическая область видимости была очень хорошо определена в ответах выше: переменные с лексической областью доступны - или доступны - на локальном уровне функции, в которой они были определены.

Однако - поскольку это не сфокусировано на ФП - динамический анализ не получил большого внимания, и внимание, которое он получил, означает, что ему, вероятно, нужно немного больше (это не критика других ответов, а скорее «о , этот ответ заставил нас пожелать, чтобы было немного больше "). Итак, вот еще немного:

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

... [I] n динамическая область видимости (или динамическая область действия), если область действия имени переменной является определенной функцией, то ее область действия - это период времени, в течение которого функция выполняется: во время выполнения функции имя переменной существует и привязан к своей переменной, но после возврата из функции имя переменной не существует.

0

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

Интерпретация подразумевает отслеживание трех вещей:

1) Состояние, а именно: переменные и ссылочные области памяти в куче и стеке.

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

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

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

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

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

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

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

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

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

3

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

Посмотрите, как работает лексическая область видимости в Лиспе, если вы хотите больше подробностей. Выбранный ответ Кайл Кронин в Динамические и лексические переменные в 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 
3

что переменная, определенная вне функции, может быть доступна внутри другой функции, определенной после объявления переменной. Но обратное неверно, переменные, определенные внутри функции, не будут доступны вне этой функции.

Эта концепция широко используется в замыканиях в Javascript.

Допустим, у нас есть следующий код.

var x = 2;
var add = function() {
var y = 1;
return x + y;
};

Теперь, когда вы вызываете add () -> это напечатает 3.

Так, функция add () обращается к глобальной переменной x, которая определена перед функцией метода add. Это вызвано из-за лексической области видимости в javascript.

0

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

function grandfather() {
    var name = 'Hammad';
    // likes is not accessible here
    function parent() {
        // name is accessible here
        // likes is not accessible here
        function child() {
            // Innermost level of the scope chain
            // name is also accessible here
            var likes = 'Coding';
        }
    }
}

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

Обратите внимание, это взято изВо

Похожие вопросы