И снова здраствуйте! Мы уже писали о том, что в конце сентября в OTUS стартует новый поток курса «Fullstack разработчик JavaScript». В преддверии начала занятий продолжаем делиться с вами авторскими статьями, подготовленными специально для студентов курса. Сегодня разберем виды контекста в JavaScript. Поехали.
Автор статьи: Павел Якупов
Область видимости одна из самых важных вещей в JavaScript (и имеет место быть в большинстве современных языков программирования). Область видимости(Scope) связана с длинной жизни переменной или функции, доступом, видимостью переменных, и некоторыми другими вещами.
Область видимости в языках программирования выполняет следующие функции:
Безопасность(инкапсуляция) — переменные и функции доступны только когда они понадобятся.
Устраняет проблему конфликта имен переменных. Наличие областей видимости позволяет не «сваливать» в одну кучу все переменные, симулируя пространства имен(namespace).
Реиспользование кода — написанный код можно потом использовать, избегая «посторонних» эффектов.
На самом простом уровне, в JavaScript существует две области видимости — локальная и глобальная.
В этой статье мы также затронем такую область видимости, как лексическая и блочная.
Когда вы открываете документ в JavaScript и начинаете писать код, вы попадаете в глобальную область видимости.
Все что создается в глобальной области видимости — переменные, функции — доступны из любой точки в программе. Также глобальные переменные доступны все время работы вашего приложения и удаляются только когда программа заканчивает свою работу.
Многие новички поначалу слишком часто используют глобальные переменные — так программировать несколько проще, однако это считается плохой практикой, и часто приводит к нестабильно работающим программам, которые в итоге используют куда больше памяти, чем им на самом деле нужно. Ведь если бы переменные были бы надежно инкапсулированы внутри функций, в которых они используются, по окончанию работы функции они были бы удалены из памяти с помощью сборщика мусора( Garbage collector), и прекратили занимать клиентскую память, которая не бесконечная.
Переменные, которые объявлены локально, доступны только в той области видимости, где они были объявлены.
Самый простой способ создать новую область видимости — это создать новую функцию. Переменная, созданная внутри функции, доступна только изнутри. Кроме того, локальную область видимости можно получить с помощью блочной области видимости(будет разобрано ниже).
Итак, что такое лексическая область видимости? Выражаясь простым языком — это способность внутренней функции получать доступ к внешней области видимости. Здесь стоит обратиться к практике замыканий. О них, наверное, можно написать еще пару статей, но я приведу быстро один классический пример:
Пока что мы только обсудили области видимости, которые связаны с работой функций и фигурных скобок{}, а различия в работе var и let мы обсудили только косвенно.
Как работает директива var? При объявлении переменной с её помощью в глобальной области видимости имя переменной приписывается как свойство глобальному объекту window(если мы подразумеваем браузер) и остается там все время работы программы. В тоже время как блочная область видимости, такая как {}( и куда вполне логично включаются и if, for, while и все остальные).
Кроме того, есть еще одна особенность let и const — объявленные в одной области видимости, они потом не могут быть объявлены еще раз в этой же( ну недовольство интерпретатора здесь выглядит вполне логично).
Особенности областей видимости при объявлении новой функции как «new Function». Данный вариант создания функции используется достаточно редко, но иногда это может потребоваться.
Пример синтаксиса:
Обычно функция запоминает, где она родилась(Lexical Environment), но когда функция создается с использованием конструкции new Function, в её переменные окружения записываются не окружающие ее переменные, как в обычной ситуации, а только объявленные глобально.
Обсуждая области видимости, мы не могли с вами не коснуться темы поднятия области переменных. Интерпретатор, который считывает код, на самом деле читает его два раза: он читает функции, объявленные как function declaraton, и читает глобальные переменных, объявленные глобальные с помощью переменной var. Однако переменным записывается не их объявленные значения, а значение undefined.
Пускай эта тема относится только косвенно к областям видимости, но иногда эти знания могут пригодиться.
Всем спасибо! Надеюсь, кому-то эта статья была полезной!
Полезные ссылки:
developer.mozilla.org/en-US/docs/Glossary/Scope
developer.mozilla.org/ru/docs/Web/JavaScript/Closures
2ality.com/2015/02/es6-scoping.html
learn.javascript.ru/new-function
habr.com/ru/company/otus/blog/466873
Автор статьи: Павел Якупов
Цель данной статьи состоит в том, чтобы читатель понял основные концепции областей видимости, которые используются в JavaScript.
Область видимости одна из самых важных вещей в JavaScript (и имеет место быть в большинстве современных языков программирования). Область видимости(Scope) связана с длинной жизни переменной или функции, доступом, видимостью переменных, и некоторыми другими вещами.
Зачем вообще нам нужна это область видимости?
Область видимости в языках программирования выполняет следующие функции:
Безопасность(инкапсуляция) — переменные и функции доступны только когда они понадобятся.
Устраняет проблему конфликта имен переменных. Наличие областей видимости позволяет не «сваливать» в одну кучу все переменные, симулируя пространства имен(namespace).
Реиспользование кода — написанный код можно потом использовать, избегая «посторонних» эффектов.
Типы областей видимости
На самом простом уровне, в JavaScript существует две области видимости — локальная и глобальная.
В этой статье мы также затронем такую область видимости, как лексическая и блочная.
Глобальная область видимости
Когда вы открываете документ в JavaScript и начинаете писать код, вы попадаете в глобальную область видимости.
Все что создается в глобальной области видимости — переменные, функции — доступны из любой точки в программе. Также глобальные переменные доступны все время работы вашего приложения и удаляются только когда программа заканчивает свою работу.
Многие новички поначалу слишком часто используют глобальные переменные — так программировать несколько проще, однако это считается плохой практикой, и часто приводит к нестабильно работающим программам, которые в итоге используют куда больше памяти, чем им на самом деле нужно. Ведь если бы переменные были бы надежно инкапсулированы внутри функций, в которых они используются, по окончанию работы функции они были бы удалены из памяти с помощью сборщика мусора( Garbage collector), и прекратили занимать клиентскую память, которая не бесконечная.
Локальная область видимости
Переменные, которые объявлены локально, доступны только в той области видимости, где они были объявлены.
Самый простой способ создать новую область видимости — это создать новую функцию. Переменная, созданная внутри функции, доступна только изнутри. Кроме того, локальную область видимости можно получить с помощью блочной области видимости(будет разобрано ниже).
function foo(){
let x = 15; }
//console.log(x); error
{
let y = 14; }
// console.log(y); тоже error
{
var z = 13; }
console.log(z); //опять var нам смешивает карты,
//потому что на нем не срабатывает блочная область
//видимости - теперь 13
Лексическая область видимости
Итак, что такое лексическая область видимости? Выражаясь простым языком — это способность внутренней функции получать доступ к внешней области видимости. Здесь стоит обратиться к практике замыканий. О них, наверное, можно написать еще пару статей, но я приведу быстро один классический пример:
sum(5)(5) //как сделать чтобы это работало?
function sum(a){
var add = function(b){
return a+b;
}
return add;
}
console.log(sum(5)(5)); // 10 возможно надо
//отправиться в Хогвартс чтобы это понять
Блочная область видимости
Пока что мы только обсудили области видимости, которые связаны с работой функций и фигурных скобок{}, а различия в работе var и let мы обсудили только косвенно.
Как работает директива var? При объявлении переменной с её помощью в глобальной области видимости имя переменной приписывается как свойство глобальному объекту window(если мы подразумеваем браузер) и остается там все время работы программы. В тоже время как блочная область видимости, такая как {}( и куда вполне логично включаются и if, for, while и все остальные).
Кроме того, есть еще одна особенность let и const — объявленные в одной области видимости, они потом не могут быть объявлены еще раз в этой же( ну недовольство интерпретатора здесь выглядит вполне логично).
let x = 15;
console.log(x); // все отлично
{
let x = 16; // о все по прежнему работает хорошо
console.log(x) // потому как это разные области видимости все работает нормально
let x = 17; // вот теперь у нас интерпретатор сообщит об ошибке, потому что мы переопределили переменную в этой области
}
new Function
Особенности областей видимости при объявлении новой функции как «new Function». Данный вариант создания функции используется достаточно редко, но иногда это может потребоваться.
Пример синтаксиса:
//let newFunc = new Function([arg1, arg2…argN], functionBody);
let mult = new Function(‘a’, ‘b’, ‘return a * b’);
console.log(mult(3,4));
Обычно функция запоминает, где она родилась(Lexical Environment), но когда функция создается с использованием конструкции new Function, в её переменные окружения записываются не окружающие ее переменные, как в обычной ситуации, а только объявленные глобально.
//здесь снова будут замыкания, так что надеюсь вас две ()() подряд уже не удивляют
let a = 3;
function outerFunc() {
var a = 2;
var func = new Function('console.log(a*a)');
return func;
}
outerFunc()(); // 9, из глобального объекта window
Hoisting(поднятие переменных)
Обсуждая области видимости, мы не могли с вами не коснуться темы поднятия области переменных. Интерпретатор, который считывает код, на самом деле читает его два раза: он читает функции, объявленные как function declaraton, и читает глобальные переменных, объявленные глобальные с помощью переменной var. Однако переменным записывается не их объявленные значения, а значение undefined.
console.log(x); // undefined
var x = 15;
console.log(y);// error
let y = 13;
Пускай эта тема относится только косвенно к областям видимости, но иногда эти знания могут пригодиться.
Всем спасибо! Надеюсь, кому-то эта статья была полезной!
Полезные ссылки:
developer.mozilla.org/en-US/docs/Glossary/Scope
developer.mozilla.org/ru/docs/Web/JavaScript/Closures
2ality.com/2015/02/es6-scoping.html
learn.javascript.ru/new-function
habr.com/ru/company/otus/blog/466873
Комментарии (4)
funca
16.09.2019 20:34Как работает директива var? При объявлении переменной с её помощью в глобальной области видимости имя переменной приписывается как свойство глобальному объекту window(если мы подразумеваем браузер)
В браузере var работает немного не так — свойства объектов живут в параллельной вселенной цепочек прототипов. Тема классно описана у http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#execution-context-stack
Aingis
Тема сто раз пережёвана, в 2019 можно было бы и затронуть ES-модули, например.
sum(5)(5)
иnew Function()
— это конечно интересно, но не то, что нужно в реальном работающем коде.Если уж говорить про такие тонкости, то тема с
eval
не раскрыта, а она может как учитывать область видимости, так и нет, в зависимости от того, как вызывать.Вообще контекстом обычно называют другую штуку. Ту, которая про
this
.