Статические переменные в javascript

Переменная

Переменная – это «именованное хранилище» для данных. Мы можем использовать переменные для хранения товаров, посетителей и других данных.

Для создания переменной в JavaScript используйте ключевое слово .

Приведённая ниже инструкция создаёт (другими словами: объявляет или определяет) переменную с именем «message»:

Теперь можно поместить в неё данные, используя оператор присваивания :

Строка сохраняется в области памяти, связанной с переменной. Мы можем получить к ней доступ, используя имя переменной:

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

Мы также можем объявить несколько переменных в одной строке:

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

Многострочный вариант немного длиннее, но легче для чтения:

Некоторые люди также определяют несколько переменных в таком вот многострочном стиле:

…Или даже с запятой в начале строки:

В принципе, все эти варианты работают одинаково. Так что это вопрос личного вкуса и эстетики.

вместо

В старых скриптах вы также можете найти другое ключевое слово: вместо :

Ключевое слово – почти то же самое, что и . Оно объявляет переменную, но немного по-другому, «устаревшим» способом.

Есть тонкие различия между и , но они пока не имеют для нас значения.
Мы подробно рассмотрим их в главе Устаревшее ключевое слово «var».

Имена переменных

В JavaScript есть два ограничения, касающиеся имён переменных:

  1. Имя переменной должно содержать только буквы, цифры или символы и .
  2. Первый символ не должен быть цифрой.

Примеры допустимых имён:

let userName;
let test123;

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

Самое интересное – знак доллара и подчёркивание также можно использовать в названиях. Это обычные символы, как и буквы, без какого-либо особого значения.

Эти имена являются допустимыми:

let $ = 1; // объявили переменную с именем «$»
let _ = 2; // а теперь переменную с именем «_»
alert($ + _); // 3

Примеры неправильных имён переменных:

let 1a; // не может начинаться с цифры
let my-name; // дефис ‘-‘ не разрешён в имени

Регистр имеет значение

Переменные с именами и – это две разные переменные.

Нелатинские буквы разрешены, но не рекомендуются

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

let имя = ‘…’;
let 我 = ‘…’;

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

Зарезервированные имена

Существует список зарезервированных слов, которые нельзя использовать в качестве имён переменных, потому что они используются самим языком.

Например: , , и зарезервированы.

Приведённый ниже код даёт синтаксическую ошибку:

let let = 5; // нельзя назвать переменную «let», ошибка!
let return = 5; // также нельзя назвать переменную «return», ошибка!

Создание переменной без использования

Обычно нам нужно определить переменную перед её использованием. Но в старые времена было технически возможно создать переменную простым присвоением значения без использования . Это все ещё работает, если мы не включаем в наших файлах, чтобы обеспечить совместимость со старыми скриптами.

// заметка: «use strict» в этом примере не используется
num = 5; // если переменная «num» раньше не существовала, она создаётся
alert(num); // 5

Это плохая практика, которая приводит к ошибке в строгом режиме:

«use strict»;
num = 5; // ошибка: num is not defined

На чем остановиться

Видя разницу между всеми предложенными вариантами развития событий, будущим программистам будет намного проще определиться, с чем конкретно им работать далее. Но, как можно было заметить, Си-семейство практически идентично друг другу.

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

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

  • Джава – идеально подходит для многопоточных и кроссплатформенных утилит;
  • C++ — часто применяется для написания софта, работающего с «железками» (драйверы, ОС);
  • Шарп – задействован как и Джава, но приносит работнику большую зарплату;
  • C – сгодится для решения некоторых элементарных задач.

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

Внимание: для того, чтобы не испытывать проблем при программировании, рекомендуется начать путь в мир кодификаций с Си, постепенно переходя на Джаве и Си-семейство «нового поколения»

Императивное программирование

Императивное программирование характеризуется в основном:

  • в исходном коде программы записываются инструкции (команды);
  • инструкции должны выполняться последовательно;
  • каждая инструкция может изменять некое глобальное “состояние” программы

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

Практически всё аппаратное обеспечение в основе своей императивное.

Неструктурное программирование

Характерно для наиболее ранних языков программирования.

В основном характеризуется:

  • строки как правило нумеруются
  • из любого места программы возможен переход к любой строке

Характерной особенностью неструктурного программирования является сложность реализации рекурсии.

Структурное программирование

В отличие от неструктурного программирования, характеризуется:

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

Концепция структурного программирования основана на теореме Бёма-Якопини:

Последовательность – это выполнение сначала одной подпрограммы, затем другой.

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

Итерация – это многократное выполнение подпрограммы пока некое булево выражение истинно.

Процедурное программирование

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

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

  • локальных переменных
  • относительно простой рекурсии

Оба этих пункта реализуются за счёт использования стека вызовов.

Объектно-ориентированное программирование

Объектно-ориентированное программирование основано на концепции “объекта”.

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

Наиболее популярной формой ООП является ООП на основе классов. В данном подходе, все объекты являются экземплярами классов, и классы определяют так же тип объектов.

Одной из альтернатив является прототипное наследование. Прототипное наследование не использует классов. Вместо этого, одни объекты могут быть объявлены “прототипами” других объектов – при этом методы и поля прототипа становятся доступны как методы и поля нового объекта (если, конечно, новый объект их не переопределяет)

Аналогия из жизни

Мы легко поймём концепцию «переменной», если представим её в виде «коробки» для данных с уникальным названием на ней.

Например, переменную можно представить как коробку с названием и значением внутри:

Мы можем положить любое значение в коробку.

Мы также можем изменить его столько раз, сколько захотим:

let message;
message = ‘Hello!’;
message = ‘World!’; // значение изменено
alert(message);

При изменении значения старые данные удаляются из переменной:

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

let hello = ‘Hello world!’;
let message;
// копируем значение ‘Hello world’ из переменной hello в переменную message
message = hello
;
// теперь две переменные содержат одинаковые данные
alert(hello); // Hello world!
alert(message); // Hello world!

Повторное объявление вызывает ошибку

Переменная может быть объявлена только один раз.

Повторное объявление той же переменной является ошибкой:

let message = «Это»;
// повторение ключевого слова ‘let’ приводит к ошибке
let message = «Другое»; // SyntaxError: ‘message’ has already been declared

Поэтому следует объявлять переменную только один раз и затем использовать её уже без .

Функциональные языки программирования

В таких языках однажды сохранённое «в коробку» значение остаётся там навсегда. Если нам нужно сохранить что-то другое, язык заставляет нас создать новую коробку (объявить новую переменную). Мы не можем использовать старую переменную.

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

Цепочки областей видимости

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

Давайте рассмотрим эту структуру вложенности:

Как вы можете видеть, bar вложен в foo. Чтобы всё это представить посмотрите на диаграмму ниже:

Мы вернёмся позже к этому примеру.

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

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

Что такое ООП?

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

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

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

Переменная

Для создания переменной в JavaScript используйте ключевое слово .

Приведённая ниже инструкция создаёт (другими словами: объявляет или определяет) переменную с именем «message»:

let message;

Теперь можно поместить в неё данные, используя оператор присваивания :

let message;
message = ‘Hello’; // сохранить строку

Строка сохраняется в области памяти, связанной с переменной. Мы можем получить к ней доступ, используя имя переменной:

let message;
message = ‘Hello!’;
alert(message); // показывает содержимое переменной

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

let message = ‘Hello!’; // определяем переменную и присваиваем ей значение
alert(message); // Hello!

Мы также можем объявить несколько переменных в одной строке:

let user = ‘John’, age = 25, message = ‘Hello’;

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

Многострочный вариант немного длиннее, но легче для чтения:

let user = ‘John’;
let age = 25;
let message = ‘Hello’;

Некоторые кодеры также определяют несколько переменных в таком вот многострочном стиле:

let user = ‘John’,
  age = 25,
  message = ‘Hello’;

…Или даже с запятой в начале строки:

let user = ‘John’
  , age = 25
  , message = ‘Hello’;

В принципе, все эти варианты работают одинаково. Так что это вопрос личного вкуса и эстетики.

вместо

В старых скриптах вы также можете найти другое ключевое слово: вместо :

var message = ‘Hello’;

Ключевое слово – почти то же самое, что и . Оно объявляет переменную, но немного по-другому, «устаревшим» способом.

Есть тонкие различия между и , но они пока не имеют для нас значения. Мы подробно рассмотрим их в главе
Устаревшее ключевое слово «var».

JavaScript Идентификаторы

Все JavaScript переменные должны быть определены с уникальным именами.

Уникальные имена называются идентификаторами.

К примеру, идентификаторы могут быть короткими именами (например, x и y) или более описательными именами (age, sum, totalVolume).

Общие правила построения для имен переменных (уникальных идентификаторов):

  • Имена переменных могут содержать буквы, цифры, символы подчеркивания и знаки доллара
  • Имена переменных должны начинаться с буквы
  • Имена переменных, также могут начинаться с $ и _ (но мы не будем использовать в этом руководстве)
  • Имена переменных чувствительны к регистру (y и Y — разные переменные)
  • Зарезервированные слова (например, ключевые слова JavaScript) нельзя использовать в качестве переменных имен

JavaScript идентификаторы чувствительны к регистру.

C Sharp vs Java

C Sharp и Java – «лексика», позволяющая реализовывать многопоточность в целях повышения производительности процессоров и операций в работе программы. Как и в прошлом случае, схожи между собой. Понимая различия между этими вариациями создания утилит, пользователь сможет подобрать конкретно себе оптимальный подход.

Чем похожи

Но для начала – о сходствах. Эти варианты:

  • имеют поддержку объектно-ориентированного программирования;
  • обладают автоматическими сборщиками «мусора»;
  • основаны на C;
  • подключаются к системам управления базами данных;
  • обладают многопоточностью.

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

В чем главные различия

Раздумывая на тему борьбы C# vs Java, пользователи должны понимать, что у всего есть свои плюсы и минусы. Может показаться, особенно новичкам, что это – два практически идентичных метода написания программного кода. Но в действительности это неверное утверждение.

Вот моменты, в которых кодификации отличаются друг от друга:

  1. Определения. C# — «лексика» многоцелевого характера общего назначения. Предусматривает строгую типизацию, поддерживает ООП. Джава – способ программирования в «общем назначении» параллельного типа. Предусматривает ООП. Разработан для того, чтобы было меньше зависимостей реализации.
  2. Разработчики. Шарп изобретен корпорацией Microsoft. Создателем Джавы выступает Sun Microsystem.
  3. Среда, в которой работают программеры. Шарп функционирует посредством CLR (Common Language Runtime). В случае с Джавой действовать предстоит через отдельную виртуальную машину – JVM.
  4. Операторные перегрузки. C# имеет поддержку перегрузки операторов. Во втором случае подобный «функционал» полностью отсутствует.
  5. Свойства классов. В Шарпе они есть, в Java – нет.
  6. Делегаты. Принцип такой же, как и со свойствами классов.
  7. IDE основного типа. Для Шарпа средой разработки IDE используется VS (Visual Studio). Джава предлагает NetBeans и Eclipse.
  8. Операторы. В Sharp есть оператор Goto, а во втором случае его нет. Здесь ситуация точно такая же, как и с Си Плюс-Плюс.
  9. Объединения, структуры. Шарп – полноценная «лексика», в которой есть упомянутые составляющие. В Джаве концепции структуры и объединений отсутствуют. И внедрить их никак не получится.

На основании всего вышесказанного можно сделать вывод о том, что Java – более простой и совершенный вариант. От Си-класса типа Шарп отличается преимущественно средой, в которой осуществляется основная работа.

Наследование статических методов

Но как будут
вести себя статические методы при наследовании классов? Предположим, что мы
хотим добавить еще одного специализированного пользователя Admin:

class Admin extends Users {
         constructor(name, old, login, psw) {
                   super(name, old);
                   this.login = login;
                   this.psw = psw;
         }
}

Мы расширяем
базовый класс Users и добавляем еще
два свойства: login и psw. Будет ли
статический метод compareOld доступен в дочернем классе Admin? Да, будет и,
далее, мы можем создать такого пользователя:

let u2 = new Admin("Федор", 19, "aaa", "0123");

и сравнить их,
вызывая статический метод через класс Admin:

console.log( Admin.compareOld(u1, u2) );

То есть, метод compareOld можно вызывать
и через класс Users и через класс Admin. Разницы
никакой не будет. Это происходит по той причине, что свойство __proto__ класса Admin ссылается на
класс Users:

Если же добавить
еще один статический метод, но уже в класс Admin:

         static createAdmin(name, old) {
                   return new this(name, old, "admin", "root");
         }

то картина будет
такой:

В методе createAdmin мы создаем
нового пользователя Admin с использованием только двух
параметров: name, old. Остальные два
задаются по умолчанию как: «admin», «root». Причем,
ключевое слово this здесь будет ссылаться на класс, указанный перед
точкой, при вызове данного метода. Например:

let u3 = Admin.createAdmin("Сергей", 33);

Здесь this ссылается на Admin, поэтому будет
создан новый объект класса Admin. А вот если мы в методе compareOld
добавим вывод:

console.log(this == Admin);

и вызовем его
двумя способами:

Users.compareOld(u1, u2);  // false
Admin.compareOld(u1, u2);  // true

то в первом
случае this будет ссылаться
на Users, а во втором –
на Admin.

Что такое глобальные переменные?

Это переменные PHP, которые «видно» везде.

Чтобы получить доступ к глобальной переменной перед ней нужно указать ключевое слово global:

<?php
global $cat;
echo $cat;

Или можно использовать супер-глобальный массив $GLOBALS:

<?php echo $GLOBALS; ?>

Глобальные переменные — это обычные переменные, которые определены в глобальной области (основной части) PHP. Чтобы понять что такое глобальная область, представьте самый первый php файл, обычно это index.php — это глобальная область кода (глобальная область видимости). Если в таком файле определить переменную, то она автоматически станет глобальной. Но если в таком файле создать функцию и определить переменную внутри этой функции, то она будет локальной — область видимости такой переменной не выходит за пределы функции. То же касается классов и их методов (функций)…

А что, если в «глобальный» файл подключается другой файл? Допустим, в главный файл index.php мы подключаем еще один файл wp-load.php — . Код этого подключенного файла также становится глобальным, и переменные напрямую определенные в этом файле автоматически становятся глобальными.

Рассмотрим на примере. Допустим, код ниже мы вставляем в файл темы functions.php, который в свою очередь подключается в глобальную область видимости и любые переменные указанные в нём напрямую, становятся глобальными.

<?php
$var = 'Привет мир!'; // эта переменная становится глобальной

// функция
function my_func(){
	echo $var;
}
my_func(); // вызов: получим ошибку уровня Notice,
		   // потому что в области видимости функции нет переменной $var

// функция
function my_func2(){
	global $var; // определим $var глобально

	// теперь $var это глобальная переменная

	echo $var; // Привет мир!

	// изменим переменную - изменится глобальная переменная
	$var = 'Пока мир';
}
my_func2(); // выведет: 'Привет мир!'

// выведем переменную $var за пределами функций
echo $var; // выведет: 'Пока мир'
		   // потому что мы изменили глобальную $var в функции my_func2()

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

Глобальную переменную можно создать из локальной области видимости, например из функции:

<?php
echo $var; // вызовет ошибку - переменная не определена

function my_func2(){
	global $var; // Создадим глобальную переменную $var

	$var = 'Привет мир';
}
my_func2(); // вызовем функцию

echo $var; // выведет 'Привет мир'

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

global $var;

// тоже самое что

$var = & $GLOBALS;

Важно! Использовать глобальные переменные нужно осторожно!

Глобальных переменных очень много и их легко изменить. Например, если в начале файлы темы header.php написать $id = 2;, то глобальная переменная $id, которая содержала ID текущей записи измениться и использовать её уже нельзя!

Подобным образом тема или плагины могут менять глобальные переменные. Но все же, среди глоб. переменных есть, скажем так «занятые», о которых должен знать каждый разработчик и не должен использовать их в качестве глоб. переменных при создании плагина или темы. Как раз этот список и приведен в этой статье.

Переменные не из этой статьи использовать в коде не рекомендую. Вместо них следует найти альтернативное решение получить нужные данные, например с помощью соответствующей функции.

Переменные (ключевые слова var, let и const)

Переменная – это именованный участок памяти для хранения данных.

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

Данные, хранящиеся в переменной, называются её значением.

В процессе выполнения программы значения переменной могут меняться. Но в определённый момент времени переменная всегда имеет какое-то одно значение.

В JavaScript до ES6 (ECMAScript 2015) объявление (создание) переменных осуществлялось с использованием только ключевого слова .

// объеявление переменной message (message - это имя переменной)
var message;

При создании переменной ей сразу же можно присвоить некоторое значение. Эту операцию называют инициализацией переменной.

Присвоение переменной значения выполняется через оператор .

// например, создадим переменную email и присвоим ей в качестве значения строку "no-reply@astr.org"
var email = 'no-reply@astr.org';
// установим переменной email новое значение
email = 'support@astr.org';

Для того чтобы получить значение переменной к ней нужно просто обратиться по имени.

// например, выведем в консоль браузера значение переменной email
console.log(email);

Переменная, которая объявлена без инициализации имеет по умолчанию значение .

var phone;
// например, выведем в консоль браузера значение переменной phone
console.log(phone); // undefined  

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

// например, объявим с помощью одного ключевого слова var сразу три переменные, и двум из них сразу присвоим значения
var
  price = 78.55,
  quantity = 10,
  message;

Объявление переменных с помощью let и const

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

В чем отличия от ?

1. Переменная объявленная посредством имеет область видимости, ограниченную блоком. Т.е. она видна только внутри фигурных скобок, в которых она создана, а также в любых других скобках, вложенных в эти. Вне них она не существует.

{
  let name = 'John';
  console.log(name); // "John"
  {
    console.log(name); // "John"
  }
}
console.log(name); // Uncaught ReferenceError: name is not defined

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

Такая переменная будет видна за пределами блока, в котором она создана.

{
  var name = 'John';
  console.log(name); // "John"
  {
    console.log(name); // "John"
  }
}
console.log(name); // "John"

2. Переменные, созданные с помощью не поднимаются к началу текущего контекста, т.е. hoisting для них не выполняется. Другими словами, к такой переменной нельзя обратиться до её объявления.

age = 10; // ReferenceError: Cannot access 'age' before initialization
let age = 28;

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

age = 10;
var age = 28;

Константы (const)

Мы разобрали отличия от . А что же насчёт ? Переменные, созданные с помощью ведут себя также как с . Единственное отличие между ними заключается в том, что непосредственное значение переменной созданной через вы не можете изменить. Таким образом, – это ключевое слово, предназначенное для создания своего рода констант.

const COLOR_RED = '#ff0000';

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

При попытке изменить значение константы вам будет брошена ошибка.

const COLOR_RED = '#ff0000';
COLOR_RED = '#f44336'; // Uncaught TypeError: Assignment to constant variable.

Когда переменной вы присваиваете значение, имеющее объектный тип данных, в ней уже будет храниться не сам этот объект, а ссылка на него. Это необходимо учитвать при работе с переменными в JavaScipt.

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

const COLORS = ;
// присвоить другой объект или значение константе нельзя
COLORS = []; // Uncaught TypeError: Assignment to constant variable.
COLORS = { red: '#ff0000', green: '#00ff00', blue: '#00ff00' }; // Uncaught TypeError: Assignment to constant variable.
COLORS = '#00ff00'; // Uncaught TypeError: Assignment to constant variable
// но имзменить сам объект можно
COLORS.push('#4caf50');
console.log(COLORS); // 

2. Инициализация: constructor()

constructor(param1, param2, …) это специальный метод в теле класса, который инициализирует экземпляр. Это место, где вы можете установить начальные значения для полей или выполнить любые настройки объектов.

В следующем примере конструктор устанавливает начальное значение поля name:

class User {
  constructor(name) {
    this.name = name;
  }
}

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

Внутри конструктора значение this равно вновь созданному экземпляру.

Аргументы, используемые для создания экземпляра класса, становятся параметрами конструктора:

class User {
  constructor(name) {
    name; // => 'Jon Snow'
    this.name = name;
  }
}

const user = new User('Jon Snow');

Параметр name внутри конструктора имеет значение ‘Jon Snow’.

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

В то же время класс JavaScript может иметь до одного конструктора.

Контекст выполнения

Контекст выполнения — это абстрактное понятие, которое используется в спецификации ECMAScript для оценки времени выполнения кода. Это может быть глобальный контекст — global context, в котором ваш код выполнится первым, или когда поток выполнения переходит в тело функции.

В любой момент времени выполняется только один контекст функции (тело функции). Вот почему JavaScript является однопотоковым, так как единовременно может выполняться только одна команда. Обычно браузеры поддерживают этот контекст с помощью стека — stack. Стек — структура данных, выполняемая в обратном порядке: LIFO — «последним пришёл — первым вышел». Последнее, что вы добавили в стек, будет удалено первым из него. Это происходит из-за того, что мы можем только добавить или удалить элементы из верхушки стека. Текущий или «выполняющийся» контекст исполнения — всегда верхний элемент стека. Он выскакивает из стека, когда код в текущем контексте полностью разобран, позволяя следующему верхнему элементу стека взять на себя контекст выполнения.

Кроме того, если контекст уже выполняется, это не означает, что ему нужно завершить своё выполнение, прежде чем другой контекст выполнения сможет начать работу. Бывают случаи, когда контекст приостанавливается и другой контекст начинает работу. Прерванный контекст может быть позже забран обратно наверх в том месте, где он был приостановлен. В любое время один контекст может быть заменён другим, и этот новый контекст поместится в стек, став текущим контекстом выполнения.

Для наглядности запустите в консоли код, который вы видите ниже:

Затем, когда boop возвратится, он удалится из стека, и bar продолжит работу:

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

  • Оценка состояния кода — любое состояние необходимо выполнить, приостановить и возобновить определение кода, связанного с этим контекстом выполнения.
  • Функция — объект функции, который оценивает контекст выполнения или null, если контекст был определён как script или модуль.
  • Область — набор внутренних объектов, глобальное окружение ECMAScript, весь код ECMAScript, который находится в пределах этого глобального окружения и другие связанные с ним состояния и ресурсы.
  • Лексическое окружение — используется для разрешения ссылок идентификатора кода в этом контексте исполнения.
  • Переменное окружение — лексическое окружение, чья запись окружения — EnvironmentRecord имеет связи, созданные заявленными переменными — VariableStatements в этом контексте выполнения.

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

Заметка: c технической точки зрения, окружение переменных и лексическая область видимости используются для реализации замыканий. Но для простоты мы заменим его на «окружение». Для детального объяснения разницы между лексическим и переменным окружением читайте статью Акселя Раушмайера.

Пример: сравнение объектов

Ещё один хороший способ применения – сравнение объектов.

Например, у нас есть объект для журналов. Журналы можно сравнивать – по толщине, по весу, по другим параметрам.

Объявим «стандартную» функцию сравнения, которая будет сравнивать по дате издания. Эта функция сравнения, естественно, не привязана к конкретному журналу, но относится к журналам вообще.

Поэтому зададим её как статический метод :

В примере ниже эта функция используется для поиска самого раннего журнала из массива:

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

Например, метод можно сделать статическим. Он будет форматировать дату «как это принято в журналах», при этом его можно использовать в любом месте кода, не обязательно создавать журнал.

Например:

Поднятие в Javascript (пример с переменной var)

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

1

2console.log(years);

3

4

5var years =100;

Давайте, ради интереса, также выведем в лог произвольную переменную, которой у нас вообще не существует:

1

2console.log(years);

3

4

5console.log(test);

6

7

8

9

10

11

12

13var years =100;

То есть, когда мы выводим в лог значение переменной years, до ее создания, происходит следующее:

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

2

3

4

5console.log(years);

6

7

8

9var years =100;
  1. В самомом конце наша переменная обновляется со значением 100
1

2

3

4

5console.log(years);

6

7

8

9var years =100;

10

11console.log(years);

12

13

9. Заключение

Классы JavaScript инициализируют экземпляры конструкторами, определяют поля и методы. Вы можете прикрепить поля и методы даже к самому классу, используя ключевое слово static.

Наследование реализуется с помощью ключевого слова extends: вы можете легко создать дочерний класс из родительского. Ключевое слово super используется для доступа к родительскому классу из дочернего класса.

Чтобы воспользоваться преимуществами инкапсуляции, делайте поля и методы приватными, чтобы скрыть внутренние детали ваших классов. Имена приватных полей и методов должны начинаться с #.

Классы в JavaScript становятся все более удобными в использовании.

Spread the love

4
Поделились

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: