Переменные и константы
Любая программа или приложение должны хранить данные. Этими данными могут быть любимый цвет пользователя, содержимое корзины, имя пользователя или что-то подобное. В Swift есть два способа хранения значений в вашем приложении:
- использование переменных;
- использование констант.
Переменная — это сущность, у которой значение можно изменить позже. Константа — это сущность, значение которой нельзя изменить позже.
Что из себя представляют переменные и константы?
Переме́нная — поименованная, либо адресуемая иным способом область памяти, адрес которой можно использовать для осуществления доступа к данным и обладающая некоторым типом. Данные, находящиеся в переменной (то есть по данному адресу памяти), называются значением этой переменной.
Переменная простыми словами — это хранилище данных. Сюда можно положить какое-то значение (например, число, строку или другой тип данных).
Наглядный пример
Еще более простой вариант представить себе переменную — подумать о том, что нас окружает. Например, переменной может быть какая-то коробка, куда можно положить все что угодно. Это может быть мяч, телефон, капуста и прочее.
Определяем, что в коробке будем хранить фрукты. На этой коробке написано «Яблоки» и это делает эту коробку уникальной. Всегда можно найти именно эту коробку по этому имени (при условии, что не может существовать ни одной другой коробочки с таким именем).
И в дальнейшем можно как угодно работать с этой коробкой. В любой момент можно положить туда что-нибудь (предварительно выкинув оттуда то, что там лежало раньше), посмотреть, что там лежит, или вообще взять и выкинуть эту коробку со всем содержимым.
Положим в коробку яблоко. Раз определили, что в коробке будут храниться фрукты, то ничего кроме фруктов в неё нельзя поместить. Можно ли положить вместо яблока какой-то другой фрукт? Можно, но на коробке написано «Яблоки», поэтому, при работе с коробкой, ожидается, что в ней будут именно яблоки. Если в ней будут другие фрукты, то это может вызвать путаницу. На яблоки можно, например, посмотреть, изменить их количество или произвести с яблоком какие-то ещё действия.
Переменную в любой программе необходимо объявлять. То есть достать эту коробку перед тем, как положить в неё яблоко.
В современных приложениях переменных может быть сколько угодно много. Например, в одной коробке хранится яблоко, в другой — конфета.
Таким образом, коробка будет переменной; то, что может хранить коробка (“фрукты”) — будет называться типом данных переменной; название коробки (“Яблоки”) — это имя переменной; то, что лежит в коробке, будет называться значением переменной.
При этом важно понимать, что концепция переменных — это очень сложный механизм работы с памятью, который просто скрыт от программиста современными операционными системами и высокоуровневыми языками программирования.
Зачем нужны переменные и как они работают
Все элементы компьютера (ноутбука, смартфона) в общем случае можно разделить на три основных функциональных уровня: аппаратный, операционной системы и программный.
Аппаратный уровень представлен физическим оборудованием компьютера. Это та основа, на которой базируются остальные уровни. Самые важные элементы аппаратного уровня — это центральный процессор (CPU, Central Processing Unit) и оперативная память.
Процессор — сердце любого современного электронного устройства (персонального компьютера, планшета, смартфона и т.д.). Компьютеры постоянно обрабатывают числа и вычисляют значения, выполняя простые арифметические и логические операции. Все данные в любом компьютере превращаются в числа. Причем неважно, говорим о фотографии, песне или книге, — для компьютера все это лишь нули и единицы. CPU как раз и предназначен для работы с числами. Он получает на вход несколько значений и, в зависимости от переданной команды (инструкции), выполняет с ними заданные операции.
Данные, с которыми работает процессор, хранятся во временном хранилище — оперативной памяти.
Оперативная память — это основное средство хранения данных, используемое программами в ходе их функционирования. Память компьютера состоит из миллионов отдельных ячеек, каждая из которых может хранить небольшой объем информацию. Каждая ячейка имеет уникальный адрес, по которому ее можно найти в памяти. Но размер ячейки не позволяет хранить в ней большое количество данных, по этой причине ячейки логически объединяются в хранилища данных.
Хранилище может объединять произвольное количество ячеек, его размер определяется количеством записанной информации и при необходимости может изменяться. Как и ячейка памяти, хранилище имеет уникальный адрес, по которому может быть получено хранящееся в нем значение (обычно он соответствует адресу первой входящей в него ячейки).
Адреса ячеек (а соответственно и адреса хранилищ) — это наборы цифр, которые очень неудобны для использования программистами.
Примечание. Данное описание устройства и работы оперативной памяти упрощено для восприятия.
Во времена, когда программы писались на машинном коде, программист должен был запоминать в какой участок памяти он записал нужное значение. Представьте, как усложнялся процесс написания программы, когда возникала необходимость работы с несколькими значениями. Адрес байта памяти есть число, которое мало о чем говорит. Большой объем памяти создает трудности программисту.
С первыми языками программирования появилась полезная возможность связывания определенного участка оперативной памяти с символьным названием (набором символов). По сравнению с адресом, название переменной может отражать содержимое этого участка памяти. Кроме имени, у переменной есть её тип. Эти два свойства переменной (название и тип) определяют нужный участок памяти и способ его использования. В большинстве случаев именно тип переменной определяет сколько байтов памяти захватит переменная.
По этой причине Swift, как и любой другой язык высокого уровня, вместо числовых адресов позволяет указывать удобные и понятные имена (идентификаторы) для хранения данных в оперативной памяти. Такие имена использовать намного проще, чем запоминать и передавать в программу настоящие адреса ячеек.
По идентификатору можно не только получить значение, но и изменить его.
Примечание. Оперативная память хранит нужные данные так долго, как этого требует приложение (ограничиваясь лишь временем, пока оно запущено). Соответственно, если программа завершила выполнение своей работы, то ячейка памяти стирает свои данные и переменная исчезает. Для того, чтоб программа хранила свои данные и после завершения выполнения кода (для постоянного долговременного хранения информации) необходимо использовать постоянные места хранения — другие элементы аппаратного уровня, например HDD или SSD, сторонние серверы хранения и обменна данными.
Операционная система (ОС) — это посредник между программой и аппаратной частью. Благодаря ОС приложения могут использовать все возможности компьютера: воспроизводить музыку, отображать графику на экране, передавать данные по Wi-Fi и Bluetooth, выполнять математические операции и многое другое.
Операционная система предоставляет интерфейсы, которые используются в ходе работы программного обеспечения.
Программный уровень — это все программы, которые работают на вашем компьютере в среде операционной системы. Каждая программа решает множество задач и для этого взаимодействует с уровнем операционной системы и аппаратным уровнем.
- С целью решения задачи приложение может передать операционной системе команды.
- Система обрабатывает полученные данные и передает их на аппаратный уровень.
- Аппаратный уровень производит необходимые операции, используя при этом техническую составляющую устройства, после чего передает данные обратно на уровень операционной системы и далее на программный уровень.
Каждая задача, выполняемая приложением, в результате может привести к выполнению сотен и тысяч инструкций в процессоре.
Программный уровень подразумевает использование языка программирования, так как программы создаются именно с его помощью.
Каждая программа взаимодействует с данными, которые могут быть получены разными способами: загружены с жесткого диска, введены пользователем, получены из Сети и т.д. Часто эти данные нужно не просто получить, обработать и отправить в указанное место, но и сохранить, чтобы использовать в будущем. Так, например, получив ваше имя (предположим, что вы ввели его при открытии приложения), программа запишет его в память и при необходимости будет получать его оттуда, чтобы отобразить в соответствующем месте графического интерфейса.
Выше, когда мы говорили об оперативной памяти, то упоминали понятие хранилища данных.
Хранилище данных — это виртуальный объект со следующими свойствами:
- записанное значение;
- идентификатор (имя);
- тип информации, для хранения которой предназначено хранилище (числовой, строковый и др.).
В программировании на Swift при работе с хранилищами данных выделяют два важнейших понятия: объявление и инициализация.
- Объявление — это создание нового объекта (хранилища данных).
- Инициализация — это присвоение значения объекту.
Практически весь процесс программирования заключается в том, чтобы создавать (объявлять) объекты, задавать (инициализировать) им значения, получать эти значения из памяти и производить с ними операции.
В Swift выделяют два вида хранилищ данных:
- переменные, объявляемые с помощью ключевого слова var ;
- константы, объявляемые с помощью ключевого слова let .
Любое хранилище, неважно, какого вида, имеет три важнейших свойства:
- имя, по которому можно проинициализировать новое или получить записанное ранее значение. Ранее мы назвали его идентификатором;
- тип данных, определяющий множество значений, которые могут храниться в этом хранилище (целые числа, строки и т.д.);
- значение, которое в данный момент находится в хранилище.
В общем случае, переменная – это поименованный участок оперативной памяти, используемый для временного хранения данных.
В переменных хранятся определенные данные, которые можно впоследствии использовать в программе. Для того, чтобы переменная появилась, необходимо ее объявить (зарезервировать ячейку памяти под определенные данные).
Переменные в программе нужны не только для хранения данных, но и для различных операций с ними. Также в ходе выполнения программы можно, например, это значение достать и положить другое. Это будет значить, что переменная изменилась.
Такое объяснение достаточно близко к тому, как на самом деле устроено хранение в памяти компьютера: переменная — это выделенная область памяти, в которой хранятся наши данные. Константа — это особый тип переменной, значение которой нельзя изменить.
- можно создавать и удалять переменные, в зависимости от потребности функционирования программы;
- в переменной можно хранить информацию;
- можно извлекать из переменной информацию, что не повлияет на значение самой переменной;
- в переменную можно записать новые данные.
Типы переменных. Статическая и динамическая типизация переменных
Как было отмечено выше, у переменной есть такое свойство, как тип.
Типизация — это прием, широко используемый в языках программирования для распознавания введенных переменных и определения того, как можно их далее использовать.
Если обратиться к примеру с коробкой выше, то типизация – это возможность разделить коробки по возможному содержимому. То есть, когда создаём коробку, то кроме имени указываем, что в ней может располагаться. И тогда, в коробку для телефона нельзя положить ничего другого.
Это позволяет дополнительно защититься от ошибок, потому что будет заранее известно, что будет в коробке, и будешь понятно, как нужно будет взаимодействовать с содержимым.
Типизация может быть как статическая — когда типы переменных задаются на этапе компиляции, так и динамическая — когда тип определяется и присваивается в ходе выполнения программы. В последнем случае иногда говорят, что переменная не имеет типа, хотя данные, содержащиеся в ней, безусловно, относятся к определённому типу данных, но выясняется это уже во время выполнения программы.
В большинстве случаев статическая типизация позволяет уменьшить затраты ресурсов при выполнении программы, поскольку для динамической типизации требуются затраты ресурсов на выяснение типов данных их приведение в выражениях с смешанными типами. Статическая типизация позволяет перекладывать проверку типов на этапе компиляции программы — статическая типизация позволяет экономить ресурсы при выполнении программы, так как все типы переменных известны заранее и нет необходимости вычислять их в ходе выполнения. Это также упрощает обнаружение ошибок ещё на этапе разработки, когда их исправление обходится менее дорого (можно предотвратить многие ошибки на этапе компиляции программы).
Язык Swift — является языком программирования со статической типизацией. Тип данных указывается явно или неявно. Изменить тип данных у переменной после его назначения — нельзя.
Более детально про типы данных можно узнать в отдельной статье. См. ссылки внизу.
Виды типов данных переменных
Данные для работы программы хранятся в оперативной памяти (ОЗУ). Условно в компьютере существует два вида памяти для работы приложения:
- Стек (Stack) – быстрая память, но сильно ограниченная по размеру;
- Куча (Heap) – память, ограниченная только размером оперативной памяти, но при этом значительно более медленная, чем стек.
Таким образом несложно понять, что стек хранит небольшие по размеру данные, к которым обеспечивается доступ с наибольшей скоростью, а в куче хранятся сложные сущности, содержащие большой объем данных.
В Swift есть два вида типов данных:
- Ссылочные (Reference Types) – хранятся в куче (сложные типы и классы);
- Значимые (Value Types) – хранятся в стеке (базовые примитивные типы).
Базовые типы данных относятся к значимым типам и хранятся в стеке.
Более детально про типы данных и работу с памятью можно узнать в отдельных статьях. См. ссылки внизу.
Локальные и глобальные переменные. Области видимости
Теперь стоит поговорить о таком понятии, как область видимости переменных, или просто область видимости.
Область видимости переменных — это область программы, в пределах которой имя переменной остается связанным с ее значением, то есть позволяет посредством себя обратиться к переменной. За пределами области видимости то же самое имя может быть связано с другой переменной или функцией либо быть свободным (не связанным ни с какой из них).
По зоне видимости различают локальные и глобальные переменные. Первые доступны только конкретной подпрограмме, вторые — во всей программе. С распространением модульного и объектного программирования, появились ещё и общие переменные (доступные для определённых уровней иерархии подпрограмм). Ограничение видимости может производиться путём введения пространств имён.
Ограничение зоны видимости придумали как для возможности использовать одинаковые имена переменных (что разумно, когда в разных подпрограммах переменные выполняют похожую функцию), так и для защиты от ошибок, связанных с неправомерным использованием переменных (правда, для этого программист должен владеть и пользоваться соответствующей логикой при структуризации данных).
Более детально про области видимости можно узнать в отдельной статье. См. ссылки внизу.
Как сказано выше, переменную можно создать, прочитать, изменить и удалить. Константу изменить нельзя.
Создание (Объявление) переменных и констант
Для того, чтоб работать с переменной, её необходимо сначала создать. Создание объектов (переменных, констант, функций, разных типов и пр.) называется объявлением. Объявляя какой-то объект, мы как бы говорим: “Создаю такой-то определенный объект”.
Общая форма объявления переменной (константы):
Здесь объявляется переменная number , которая имеет тип Int . Затем она устанавливает значение константы — 10 .
- var — это ключевое слово, которое указывает на объявление переменной;
- number — это имя переменной;
- : — разделяет имя и тип переменной;
- Int — это тип переменной;
- = — используется для присвоения значения переменной;
- 10 — это значение переменной.
После объявления — имя и тип данных изменить нельзя.
Итак, происходит три действия: объявление, определение типа и инициализация.
Объявление переменной или константы (Declaring Constants and Variables)
Объявляя переменную или константу мы сообщаем программе, что они сейчас будут созданы.
В Swift вы можете создавать переменные с помощью ключевого слова var и константы с помощью ключевого слова let .
Имя переменной или константы должно быть уникальным в той области видимости, в которой она объявлена. Возможность доступа к ячейке памяти по имени переменной или константе должна быть однозначной и конкретной.
Определение типа переменной или константы (Type annotations)
Swift — язык программирования со строгой типизацией. Это обозначает, что обязательно должен быть определен тип данных.
Если сразу указываем значение, то Swift автоматически определяет тип данных значения исходя из литералов значения. Если же значение не указано, то Swift не знает, какого типа данные в ней будут храниться и ему нужно явно указать этот тип.
Таким образом, объявить переменную можно и без указания значения. Но тогда нужно указать тип данных будущего значения — аннотация типа.
В этом примере добавляется обозначение типа для переменной с именем welcomeMessage , чтобы обозначить, что переменная может хранить строковый тип данных — String . Теперь переменной welcomeMessage можно присвоить любое текстовое значение, без каких либо ошибок:
Можно создать несколько переменных одного типа в одной строке. Для этого следует указать ключевое слово для объявления переменных ( var для переменных, let для констант). Затем указать имена переменных, разделяя их запятыми. И после последнего имени переменной указать необходимый тип данных:
Инициализация переменной или константы
Без присвоения начального значения переменная просто объявлена, а с начальным значением она еще и инициализирована.
Инициализация — это процесс назначения (присваивания) начального значения переменной. Таким образом при инициализации в память записываются какие-то определённые данные и работая с переменной — можно получить доступ к этим данным. Переменная при этом запущена в работу, ей присвоено начальное значение, она инициализирована.
Назначение значения называется присвоением значения и выполняется с помощью оператора присвоения = .
Выражение “присвоить переменной х значение value ” означает назначить значение value переменной х — х = value .
Когда переменная объявлена без начального значения, т.е. она еще не инициализирована, не готова полностью к работе.
Три действия — объявление, определение типа, инициализация
Таким образом, есть три действия — объявление, определение типа и инициализация. Их можно записать в одном выражении:
Неявное представление типа — без указания типа переменной. Тип переменной выбирает Swift на основание данных с которыми инициализируется переменная.
Swift рекомендует экономить время, если есть значение, он может самостоятельно определить тип данных.
В этом случае, Swift определит тип переменной исходя из типа присваиваемого значения. Если тип установить невозможно, то следует указывать тип данных переменной явно.
Обратите внимание, что “голого” объявления переменной не может быть. Должно быть обязательно объявление с какой-то второй операцией — или с присвоением значения или с определением типа данных значения. И можно применять сразу три действия, но нельзя только одно.
Объявление переменной или константы происходит один раз в одной области видимости. Для дальнейшей работы (получения значение, присваивания нового значения) следует обратиться к переменной (константе) по имени.
После объявления переменной или константы изменить её тип данных нельзя.
Какие значения можно присвоить?
Можно присвоить те значения, тип данных которых соответствует типу данных переменной или константы. Если тип данных для переменной или константы при инициализации задаётся неявно — с помощью определения типа значения — то можно проинициализировать переменную (константу) со значением любого типа. В дальнейшем, после инициализации, переменной (константе) можно присвоить значение только с тем типом, с которым она была проинициализированна.
Переменной можно присвоить любые значения, которые могут быть сохранены в память. Эти значения можно указать с помощью литералов:
Литералы — это представления фиксированных значений в программе. Это могут быть числа, символы, строки и т.д. Например, «Hello, World!», 12, 23.0, «C» и т.д.
Литералы часто используются для присвоения значений переменным или константам. Например:
В приведенном выше выражении siteName — это переменная, а «Apple.com» — литерал.
Более детально про литералы можно узнать в отдельной статье. См. ссылки внизу.
Переменной можно присвоить значение другой переменной — инициализация (или присвоение) копированием:
Переменной можно присвоить значение результата выполнения операций, функций:
Можно объявить несколько констант или несколько переменных на одной строке, разделяя их запятыми:
Можно объявить несколько констант или несколько переменных на одной строке, инициализируя с помощью кортежа:
Переменные хранят разные значения. Выше были рассмотрены базовые типы данных. Теперь усложним.
В этом примере были созданы переменные, которые хранят значение
- arrayString — массива строк ( Array<String> )
- arrayInt — массива чисел ( Array<Int> )
- tuple — кортежа ( (Int, Int, Int) )
Также переменные хранят значения экземпляров сложных типов:
Также переменная может хранить в себе ссылку на функцию:
Здесь k и m хранят в себе ссылки на функции и их тип данных является функциональным.
Обратите внимание на переменную m и f из примера выше. Запишем обе переменные с их типом данных:
Переменная f имеет тип Int и значение было присвоено через анонимную функцию, которая вернула значение типа Int . То есть значение f — это число. Обратите внимание, что в конце функционального блока <> указаны круглые скобки () .
Переменная m имеет тип () -> Int и является ссылкой на анонимную функцию (замыкающее выражение). Она возвращает значение с типом Int . Переменная m записана только с помощью блока кода <> . Для обращения к переменной m следует после её имени указывать круглые скобки () .
Более детально про функции и замыкания можно узнать в отдельных статьях. См. ссылки внизу.
Названия переменных. Соглашения об именах
Дать имя константе или переменной кажется простым. Однако, довольно сложно его правильно указать. Это связано с тем, что имя должно быть описательным и коротким одновременно.
Вот основные правила присвоения имён:
- Имена переменных и констант начинаются с маленькой буквы;
- Имя переменной должно быть таким, которое максимально понятно описывает эту переменную. Например, numberofApples — лучшее имя переменной, чем a , apple или n ;
- Хорошим тоном считается называть переменные английскими словами так, чтобы при взгляде на название стало сразу понятно, что хранится в этой переменной и для чего она нужна;
- Избегайте сокращенных имен. Даже если имена длинные, пишите их по буквам;
- Если имя переменной состоит из нескольких слов, то следует использовать так называемый “верблюжий регистр” (lowerCamelCase). Другими словами, следует начинать последовательные слова с заглавных букв, например, myBigHouse , addTwoNums и т.д.;
- Также нельзя использовать пробелы или специальные символы в именах переменных. Некоторые из них вызывают ошибки, а некоторые просто плохо выглядят.
Имена переменных должны начинаться либо с буквы, либо с символа подчеркивания _ , либо со знака доллара $ . Например,
Имена переменных не могут начинаться с цифр. Например,
Swift чувствителен к регистру. Итак, А и а — разные переменные. Например,
Избегайте использования ключевых слов Swift, таких как var , String , class и т.д., в качестве имен переменных.
Чтение и изменение переменных и констант
Для того, чтоб получить значение переменной или константы, следует обратиться к ней по имени
В этом примере была объявлена переменная name и потом было получено её значение в функции print() .
Значение переменной или константы можно получить в той области видимости, в которой она объявлена.
Прежде, чем обращаться переменной или константе, она должна быть проинициализарована с каким-то значением:
Для того, чтоб изменить значение переменной, следует обратиться к ней по имени и присвоить новое значение.
В этом примере переменная numTwo была инициализирована со значением 15 . Затем её значение было изменено на значение из выражения numOne + 100 — получили значение numOne ( 10 ) и добавили к нему 100 . Теперь значение numTwo — 110 .
Внимание! Новое значение переменной должно быть того же типа, с которым переменная была объявлена. Тип данных переменной после её объявления изменить нельзя.
При этом обращаться к переменной, таким же образом как при объявлении этой переменной (с помощью ключевого слова var ) и указывать тип данных — нельзя. Это вызовет ошибку, так как программа будет воспринимать объявление — как создание новой переменной с тем же именем в той же области видимости
В этом примере переменная name была проинициализирована со значением «Bob» . Затем значение было изменено на «Charlie» . Но при попытке изменить значение переменной с помощью конструкции var name = «Jack» — фактически была попытка объявить новую переменную с тем же именем name в той же области видимости. И это привело к ошибке.
Значение константы можно получить так же, как и у переменной — обратиться к константе по имени.
Разница между переменной и константой заключается в том, что переменная может быть изменена после инициализации, а константа — нет.
После объявления константы нельзя изменить ее значение. Например, рассмотрим следующий код:
Этот код выдает ошибку:
Константы полезны для значений, которые не будут меняться. Например, если вы моделируете самолет и вам нужно указать общее количество установленных кресел, вы можете использовать константу.
При этом константы потребляют меньше ресурсов компьютера. Поэтому необходимо использовать константы и только если в дальнейшем значение будет меняться — использовать переменные.
Удаление переменных и констант
Переменные и константы существуют до тех пор, пока существует область видимости, в которой они объявлены.
После выполнения кода в локальной области видимости происходит уничтожение объявленных в этой области видимости переменных и констант. Память, которую они занимали, освобождается.
Если переменные и константы были объявлены в глобальной области видимости, то они не уничтожаются до тех пор, пока программа работает.
Также существует захват значения, для того, чтоб сохранить значение после выполнения блока кода и закрытия области видимости.
Более детально про захват значения и работу с памятью можно узнать в отдельных статьях. См. ссылки внизу.
Вычисляемые переменные
Были рассмотрены переменные, которые хранят значения. Но переменные могут быть и вычисляемыми. Вычисляемые переменные не хранят значение, а вычисляют его каждый раз при обращении к ним.
Такие переменные объявляются следующим способом:
- var — ключевое слово для объявления переменной;
- variableComputed — имя переменной;
- Int — тип переменной;
- get <> — блок кода, который возвращает значение переменной при обращении к ней;
- set <> — блок кода, который выполняется при присвоении (установки) нового значения переменной.
Блок кода get <> обязательно должен возвращать значение того типа, которое было определено для переменной.
Если значение переменной только для чтения, то блок set <> не указывается. В этом случае можно не писать обертку get <> , а только код с возвратом значения:
Если в таком виде попытаться изменить значение, то будет ошибка, которая предупреждает о том, что значение только для чтения:
Блок set <> следует указывать, если необходимо выполнить какой-то определённый код при установке значения переменной.
В этом примере, newValue — это имя по умолчанию для внутренней переменной в блоке set <> , которое принимает то значение, которое назначается (устанавливается) переменной number . Здесь, при установке значения переменной number выполняется код, который меняет значение другой переменной numberFirst . Напрямую изменить значение переменной number нельзя, так как при чтении её значения срабатывает блок get <> . Но можно сделать значение переменной number зависимым от другой переменной и менять значение этой переменной в блоке set <> . Тогда будет меняться и значение переменной number :
В этом примере, значение переменной number зависит от переменной numberFirst — это указано в блоке get <> . В блоке set <> указано изменение значение переменной numberFirst в зависимости от устанавливаемого для переменной number значения. А значит и значение для чтения переменной number будет тоже меняться.
Можно заменить newValue на другое удобное имя, указав его в блоке set <> следующим образом:
Вычисляемые переменные в основном используются в пользовательских типах данных, таких как структуры, классы, перечисления. Там переменные называются свойствами.
Более детально про хранимые и вычисляемые свойства можно узнать в отдельных статьях. См. ссылки внизу.
Зачем нужны и переменные, и константы?
На этом этапе можно задаться вопросом, зачем нужны и переменные, и константы? Не проще ли было бы иметь только переменные? Тогда константа может быть переменной, значение которой вы никогда не измените.
Причина наличия обоих проста: программисты делают ошибки. Можно случайно изменить значение, которое не должно было изменяться. Это может полностью испортить приложение.
Также константы — базовое средство оптимизации используемых мощностей.
Поэтому рекомендуется использовать в основном константы, если инициализируемое значение не планируется изменять. И только, если в дальнейшем планируется изменение значения — использовать переменные.
Переменные — место хранения необходимой информации
После прочтения последних двух статей вы знаете, что такое JavaScript, что он может сделать для вас, как использовать его вместе с другими веб-технологиями и какими он обладает функциями высокого уровня. В этой статье мы перейдём к реальным основам, рассмотрим, как работать с большинством базовых блоков JavaScript — Переменными.
Необходимые навыки: | Базовая компьютерная грамотность, базовое понимание HTML и CSS, понимание того, что такое JavaScript. |
---|---|
Цель: | Ознакомиться с основами переменных в JavaScript. |
Инструменты, которые вам нужны
В этой статье вам будет предложено ввести строки кода, чтобы проверить ваше понимание материала. Если вы используете браузер для настольных компьютеров, лучшим примером для ввода кода примера является консоль JavaScript вашего браузера (см. What are browser developer tools для получения дополнительной информации о том, как получить доступ к этому инструменту).
Также мы предоставили простую консоль JavaScript, встроенную ниже в странице, для ввода кода, если вы не используете браузер с консолью JavaScript или консоль на странице окажется для вас более комфортной.
Что такое переменные?
Переменные — это контейнер для таких значений, как числа, используемые в сложении, или строка, которую мы могли бы использовать как часть предложения. Но одна из особенностей переменных — их значение может меняться. Давайте взглянем на простой пример:
В примере, по нажатию кнопки выполнится несколько строк кода. Первая строка в функции покажет пользователю окно, где попросит ввести его имя и сохранит значение в переменной. Вторая строка отобразит приветствие с включённым введённым именем, взятым из значения переменной.
Чтобы лучше понять действие переменной здесь, давайте подумаем о том, как мы будем писать этот пример без использования переменной. Это будет выглядеть примерно так:
Вам сейчас не обязательно понимать синтаксис, который мы используем (пока!), но вы должны понять идею: если бы у нас не было доступных переменных, нам пришлось бы реализовать гигантский блок кода, который проверял, какое имя было введено, а затем отображал соответствующее сообщение для этого имени. Очевидно, что это неэффективно (код намного больше, даже для четырёх вариантов), и он просто не сработает, так как вы не можете хранить все возможные варианты.
Переменные имеют смысл, и, когда вы узнаете больше о JavaScript, они начнут становиться второй натурой.
Ещё одна особенность переменных заключается в том, что они могут содержать практически все, а не только строки и числа. Переменные могут также содержать сложные данные и даже целые функции. Об этом вы узнаете больше при дальнейшем изучении курса..
Заметьте: мы говорим, что переменные содержат значения. Это важное различие. Переменные не являются самими значениями; они представляют собой контейнеры для значений. Представьте, что они похожи на маленькие картонные коробки, в которых вы можете хранить вещи.
Объявление переменной
Чтобы использовать переменную, вы сначала должны её создать, или, если быть точнее, объявить переменную. Чтобы сделать это, мы вводим ключевое слово var, за которым следует имя, которое вы хотите дать своей переменной:
Здесь мы создаём две переменные myName и myAge. Попробуйте ввести эти строки сейчас в консоли вашего веб-браузера или в консоли ниже (можно открыть эту консоль в отдельной вкладке или в новом окне). После этого попробуйте создать переменную (или две) с вашими именами.
Примечание: в JavaScript все инструкции кода должны заканчиваться точкой с запятой (;) — ваш код может работать правильно для отдельных строк, но, вероятно, не будет, когда вы пишете несколько строк кода вместе. Попытайтесь превратить написание точки с запятой в привычку.
Теперь проверим, существуют ли эти значения в среде выполнения. Для этого введём только имя переменной.
В настоящее время они не содержат значения, это пустые контейнеры. В этом случае, когда вы вводите имена переменных, вы должны получить значение undefined . Если они не существуют, вы получите сообщение об ошибке — попробуйте сейчас ввести в консоли имя переменной ниже:
Примечание: Не путайте переменную, которая существует, но не имеет значения, с переменной, которая вообще не существует — это разные вещи.
Присвоение значения переменной
Как только переменная объявлена, ей можно присвоить значение. Для этого пишется имя переменной, затем следует знак равенства ( = ), а за ним значение, которое вы хотите присвоить. Например:
Попробуйте вернуться в консоль и ввести эти строки. Вы должны увидеть значение, которое вы назначили переменной, возвращаемой в консоли. Чтобы посмотреть значения переменных, нужно набрать их имя в консоли:
Вы можете объявить переменную и задать ей значение одновременно:
Скорее всего, так вы будете писать большую часть времени, так как запись и выполнения кода с одно строки происходит быстрее, чем выполнение двух действий на двух отдельных строках.
Примечание: Если вы пишете многострочную программу JavaScript, которая объявляет и инициализирует (задаёт значение) переменную, вы можете объявить её после её инициализации, и она всё равно будет работать. Это связано с тем, что объявления переменных обычно выполняются первыми, прежде чем остальная часть кода будет выполнена. Это называется hoisting — прочитайте var hoisting для более подробной информации по этому вопросу.
Обновление переменной
Когда переменной присваивается значение, вы можете изменить (обновить) это значение, просто указав другое значение. Попробуйте ввести следующие строки в консоль:
Правила именования переменных
Вы можете назвать переменную как угодно, но есть ограничения. Как правило, вы должны придерживаться только латинских символов (0-9, a-z, A-Z) и символа подчёркивания.
- Не рекомендуется использование других символов, потому что они могут вызывать ошибки или быть непонятными для международной аудитории.
- Не используйте символы подчёркивания в начале имён переменных — это используется в некоторых конструкциях JavaScript для обозначения конкретных вещей.
- Не используйте числа в начале переменных. Это недопустимо и приведёт к ошибке.
- Общепринято придерживаться так называемый «lower camel case», где вы склеиваете несколько слов, используя строчные буквы для всего первого слова, а затем заглавные буквы последующих слов. Мы использовали это для наших имён переменных в этой статье.
- Делайте имена переменных такими, чтобы было интуитивно понятно, какие данные они содержат. Не используйте только отдельные буквы / цифры или большие длинные фразы.
- Переменные чувствительны к регистру, так что myage и myAge — разные переменные.
- И последнее — вам также нужно избегать использования зарезервированных слов JavaScript в качестве имён переменных — под этим мы подразумеваем слова, которые составляют фактический синтаксис JavaScript! Таким образом, вы не можете использовать слова типа var , function , let , и for для имён переменных. Браузеры распознают их как разные элементы кода, и поэтому возникают ошибки.
Примечание: По ссылке можно найти довольно полный список зарезервированных ключевых слов: Lexical grammar — keywords.
Примеры хороших имён переменных:
Примеры плохих имён переменных:
Примеры имён переменных, которые вызовут ошибки:
Попытайтесь создать ещё несколько переменных прямо сейчас, используя знания, изложенные выше.
Типы переменных
Есть несколько различных типов данных, которые мы можем хранить в переменных. В этом разделе мы кратко опишем их, а затем в будущих статьях вы узнаете о них более подробно.
Числа (Numbers)
Вы можете хранить числа в переменных (целые числа, такие как 30, или десятичные числа, такие как 2.456, также называемые числами с плавающей точкой или с плавающей запятой). Вам не нужно объявлять типы переменных в JavaScript, в отличие от некоторых других языков программирования Если давать переменной значение числа,кавычки не используются:
Строки (‘Strings’)
Строки — это фрагменты текста. Когда вы даёте переменной значение строки, вам нужно обернуть её в одиночные или двойные кавычки, в противном случае JavaScript попытается проиндексировать её как другое имя переменной.
Логические (Booleans)
Booleans — истинные / ложные значения — они могут иметь два значения: true или false. Они обычно используются для проверки состояния, после чего код запускается соответствующим образом. Вот простой пример:
В действительности вы чаще будете использовать этот тип переменных так:
Здесь используется оператор «меньше» (<), чтобы проверить, является ли 6 меньше 3. В данном примере, он вернёт false, потому что 6 не меньше 3! В дальнейшем вы узнаете больше о таких операторах.
Массивы (Arrays)
Массив — это один объект, который содержит несколько значений, заключённых в квадратные скобки и разделённых запятыми. Попробуйте ввести следующие строки в консоль:
Как только эти массивы определены, можно получить доступ к каждому значению по их местоположению в массиве. Наберите следующие строки:
Квадратные скобки указывают значение индекса, соответствующее позиции возвращаемого значения. Возможно, вы заметили, что массивы в JavaScript индексируются с нулевой отметкой: первый элемент имеет индекс 0.
В следующей статье вы узнаете больше о массивах.
Объекты (Objects)
В программировании объект представляет собой структуру кода, который моделирует объект реальной жизни. У вас может быть простой объект, представляющий автостоянку, и содержит информацию о её ширине и длине; или вы можете иметь объект, который представляет человека, и содержит данные о его имени, росте, весе, на каком языке он говорит, как сказать ему привет и многое другое.
Попробуйте ввести следующую строку в консоль:
Чтобы получить информацию, хранящуюся в объекте, вы можете использовать следующий синтаксис:
Мы больше не будем рассматривать объекты в данном курсе — вы можете больше узнать о них в будущем модуле.
Динамическая типизация
JavaScript — это «динамически типизируемый язык», что означает, что в отличие от некоторых других языков вам не нужно указывать, какой тип данных будет содержать переменная (например, числа, строки, массивы и т. д.).
Например, если вы объявите переменную и присвоите ей значение, заключённое в кавычки, браузер будет обрабатывать переменную как строку:
Он всё равно будет строкой, даже если он содержит числа, поэтому будьте осторожны:
Попробуйте ввести четыре строки выше в консоль одну за другой и посмотреть результаты. Вы заметите, что мы используем специальную функцию typeof() — она возвращает тип данных переменной, которую вы передаёте в неё. В первый раз, когда она вызывается, она должа возвращать строку, так как переменная myNumber содержит строку ‘500’ . Посмотрите, что она вернёт во второй раз, когда вы её вызовите.
Подведение итогов
К настоящему времени вы должны знать достаточно о переменных JavaScript и о том, как их создавать. В следующей статье мы остановимся на числах более подробно, рассмотрев, как сделать базовую математику в JavaScript.
Руководство по JavaScript, часть 3: переменные, типы данных, выражения, объекты
Сегодня, в третьей части перевода руководства по JavaScript, мы поговорим о разных способах объявления переменных, о типах данных, о выражениях и об особенностях работы с объектами.
Переменные
Переменная представляет собой идентификатор, которому присвоено некое значение. К переменной можно обращаться в программе, работая таким образом с присвоенным ей значением.
Сама по себе переменная в JavaScript не содержит информацию о типе значений, которые будут в ней храниться. Это означает, что записав в переменную, например, строку, позже в неё можно записать число. Такая операция ошибки в программе не вызовет. Именно поэтому JavaScript иногда называют «нетипизированным» языком.
Прежде чем использовать переменную, её нужно объявить с использованием ключевого слова var или let . Если речь идёт о константе, применяется ключевое слово const . Объявить переменную и присвоить ей некое значение можно и не используя эти ключевые слова, но делать так не рекомендуется.
▍Ключевое слово var
До появления стандарта ES2015 использование ключевого слова var было единственным способом объявления переменных.
Если в этой конструкции опустить var , то значение будет назначено необъявленной переменной. Результат этой операции зависит от того, в каком режиме выполняется программа.
Так, если включён так называемый строгий режим (strict mode), подобное вызовет ошибку. Если строгий режим не включён, произойдёт неявное объявление переменной и она будет назначена глобальному объекту. В частности, это означает, что переменная, неявно объявленная таким образом в некоей функции, окажется доступной и после того, как функция завершит работу. Обычно же ожидается, что переменные, объявляемые в функциях, не «выходят» за их пределы. Выглядит это так:
В консоль попадёт 1 , такого поведения от программы обычно никто не ждёт, выражение bNotVar = 1 выглядит не как попытка объявления и инициализации переменной, а как попытка обратиться к переменной, находящейся во внешней по отношению к функции области видимости (это — вполне нормально). Как результат, неявное объявление переменных сбивает с толку того, кто читает код и может приводить к неожиданному поведению программ. Позже мы поговорим и о функциях, и об областях видимости, пока же постарайтесь всегда, когда смысл некоего выражения заключается в объявлении переменной, пользоваться специализированными ключевыми словами. Если в этом примере тело функции переписать в виде var bNotVar = 1 , то попытка запустить вышеприведённый фрагмент кода приведёт к появлению сообщения об ошибке (его можно увидеть в консоли браузера).
Выглядеть оно, например, может так: Uncaught ReferenceError: bNotVar is not defined . Смысл его сводится к тому, что программа не может работать с несуществующей переменной. Гораздо лучше, при первом запуске программы, увидеть такое сообщение об ошибке, чем писать непонятный код, который способен неожиданно себя вести.
Если, при объявлении переменной, её не инициализируют, не присваивают ей какого-либо значения, ей автоматически будет присвоено значение undefined .
Переменные, объявленные с помощью ключевого слова var , можно многократно объявлять снова, назначая им новые значения (но это может запутать того, кто читает код).
В одном выражении можно объявить несколько переменных:
Областью видимости переменной (scope) называют участок программы, в котором доступна (видима) эта переменная.
Переменная, инициализированная с помощью ключевого слова var за пределами какой-либо функции, назначается глобальному объекту. Она имеет глобальную область видимости и доступна из любого места программы. Если переменная объявлена с использованием ключевого слова var внутри функции, то она видна только внутри этой функции, являясь для неё локальной переменной.
Если в функции, с использованием var , объявлена переменная, имя которой совпадает с именем некоей переменной из глобальной области видимости, она «перекроет» глобальную переменную. То есть, при обращении к такой переменной внутри функции будет использоваться именно её локальный вариант.
Важно понимать, что блоки (области кода, заключённые в фигурные скобки) не создают новых областей видимости. Новая область видимости создаётся при вызове функции. Ключевое слово var имеет так называемую функциональную область видимости, а не блочную.
Если в коде функции объявлена некая переменная, она видна всему коду функции. Даже если переменная объявлена с помощью var в конце кода функции, обратиться к ней можно и в начале кода, так как в JavaScript работает механизм поднятия переменных (hoisting). Этот механизм «поднимает» объявления переменных, но не операции их инициализации. Это может стать источником путаницы, поэтому возьмите себе за правило объявлять переменные в начале функции.
▍Ключевое слово let
Ключевое слово let появилось в ES2015, его, упрощённо, можно назвать «блочной» версией var . Область видимости переменных, объявленных с помощью ключевого слова let , ограничивается блоком, оператором или выражением, в котором оно объявлено, а также вложенными блоками.
Если само слово «let» кажется не очень понятным, можно представить, что вместо него используется слово «пусть». Тогда выражение let color = ‘red’ можно перевести на английский так: «let the color be red», а на русский — так: «пусть цвет будет красным».
При использовании ключевого слова let можно избавиться от неоднозначностей, сопутствующих ключевому слову var (например, не удастся два раза, используя let , объявить одну и ту же переменную). Использование let за пределами функции, скажем, при инициализации циклов, не приводит к созданию глобальных переменных.
Например, такой код вызовет ошибку:
Если же, при инициализации цикла, счётчик i будет объявлен с использованием ключевого слова var , то i будет доступно и за пределами цикла, после того, как он завершит работу.
В наши дни, при разработке JS-программ на основе современных стандартов, вполне можно полностью отказаться от var и использовать только ключевые слова let и const .
▍Ключевое слово const
Значения переменных, объявленных с использованием ключевых слов var или let , могут быть перезаписаны. Если же вместо этих ключевых слов используется const , то объявленной и инициализированной с его помощью константе новое значение присвоить нельзя.
В данном примере константе a нельзя присвоить новое значение. Но надо отметить, что если a — это не примитивное значение, наподобие числа, а объект, использование ключевого слова const не защищает этот объект от изменений.
Когда говорят, что в переменную записан объект, на самом деле имеют в виду то, что в переменной хранится ссылка на объект. Эту вот ссылку изменить не удастся, а сам объект, к которому ведёт ссылка, можно будет изменить.
Ключевое слово const не делает объекты иммутабельными. Оно просто защищает от изменений ссылки на них, записанные в соответствующие константы. Вот как это выглядит:
В константу obj , при инициализации, записывается новый пустой объект. Попытка обращения к его свойству a , несуществующему, ошибки не вызывает. В консоль попадает undefined . После этого мы добавляем в объект новое свойство и снова пытаемся обратиться к нему. В этот раз в консоль попадает значение этого свойства — 1 . Если раскомментировать последнюю строку примера, то попытка выполнения этого кода приведёт к ошибке.
Ключевое слово const очень похоже на let , в частности, оно обладает блочной областью видимости.
В современных условиях вполне допустимо использовать для объявления всех сущностей, значения которых менять не планируется, ключевое слово const , прибегая к let только в особых случаях. Почему? Всё дело в том, что лучше всего стремиться к использованию как можно более простых из доступных конструкций для того, чтобы не усложнять программы и избегать ошибок.
Типы данных
JavaScript иногда называют «нетипизированным» языком, но это не соответствует реальному положению дел. В переменные, и правда, можно записывать значения разных типов, но типы данных в JavaScript, всё-таки, есть. В частности, речь идёт о примитивных и об объектных типах данных.
Для того чтобы определить тип данных некоего значения, можно воспользоваться оператором typeof . Он возвращает строку, указывающую тип операнда.
▍Примитивные типы данных
Вот список примитивных типов данных JavaScript:
- number (число)
- string (строка)
- boolean (логическое значение)
- null (специальное значение null )
- undefined (специальное значение undefined )
- symbol (символ, используется в особых случаях, появился в ES6)
Поговорим о наиболее часто используемых типах данных из этого списка.
Тип number
Значения типа number в JavaScript представлены в виде 64-битных чисел двойной точности с плавающей запятой.
В коде числовые литералы представлены в виде целых и дробных чисел в десятичной системе счисления. Для записи чисел можно использовать и другие способы. Например, если в начале числового литерала имеется префикс 0x — он воспринимается как число, записанное в шестнадцатеричной системе счисления. Числа можно записывать и в экспоненциальном представлении (в таких числах можно найти букву e ).
Вот примеры записи целых чисел:
Вот дробные числа.
Числовые литералы (такое поведение характерно и для некоторых других примитивных типов), при попытке обращения к ним как к объектам, автоматически, на время выполнения операции, преобразуются в соответствующие объекты, которые называют «объектными обёртками». В данном случае речь идёт об объектной обёртке Number .
Вот, например, как выглядит попытка обратиться к переменной a , в которую записан числовой литерал, как к объекту, в консоли Google Chrome.
Подсказка по объектной обёртке Number
Если, например, воспользоваться методом toString() объекта типа Number , он возвратит строковое представление числа. Выглядит соответствующая команда, которую можно выполнить в консоли браузера (да и в обычном коде) так:
Обратите внимание на двойные скобки после имени метода. Если их не поставить, система не выдаст ошибку, но, вместо ожидаемого вывода, в консоли окажется нечто, совсем не похожее на строковое представление числа 5.
Глобальный объект Number можно использовать в виде конструктора, создавая с его помощью новые числа (правда, в таком виде его практически никогда не используют), им можно пользоваться и как самостоятельной сущностью, не создавая его экземпляры (то есть — некие числа, представляемые с его помощью). Например, его свойство Number.MAX_VALUE содержит максимальное числовое значение, представимое в JavaScript.
Тип string
Значения типа string представляют собой последовательности символов. Такие значения задают в виде строковых литералов, заключённых в одинарные или двойные кавычки.
Строковые значения можно разбивать на несколько частей, используя символ обратной косой черты (backslash).
Строка может содержать так называемые escape-последовательности, интерпретируемые при выводе строки в консоль. Например, последовательность \n означает символ перевода строки. Символ обратной косой черты можно использовать и для того, чтобы добавлять кавычки в строки, заключённые в такие же кавычки. Экранирование символа кавычки с помощью \ приводит к тому, что система не воспринимает его как специальный символ.
Строки можно конкатенировать с использованием оператора + .
Шаблонные литералы
В ES2015 появились так называемые шаблонные литералы, или шаблонные строки. Они представляют собой строки, заключённые в обратные кавычки ( ` ) и обладают некоторыми интересными свойствами.
Например, в шаблонные литералы можно подставлять некие значения, являющиеся результатом вычисления JavaScript-выражений.
Использование обратных кавычек упрощает многострочную запись строковых литералов:
Тип boolean
В JavaScript есть пара зарезервированных слов, использующихся при работе с логическими значениями — это true (истина), и false (ложь). Операции сравнения, например, такие, как == , === , < , > , возвращают true или false .
Логические выражения используются в конструкциях наподобие if и while , помогая управлять ходом выполнения программы.
При этом надо отметить, что там, где ожидается значение true или false , можно использовать и другие значения, которые автоматически расцениваются языком как истинные (truthy) или ложные (falsy).
В частности, ложными значениями являются следующие:
Остальные значения являются истинными.
Тип null
В JavaScript имеется специальное значение null , которое указывает на отсутствие значения. Подобные значения используются и в других языках.
Тип undefined
Значение undefined , записанное в некую переменную, указывает на то, что эта переменная не инициализирована и значение для неё отсутствует.
Это значение автоматически возвращается из функций, результат работы которых не возвращается явно, с использованием ключевого слова return . Если функция принимает некий параметр, который, при её вызове, не указан, он также устанавливается в undefined .
Для того чтобы проверить значение на undefined , можно воспользоваться следующей конструкцией.
▍Объекты
Все значения, не являющиеся примитивными, имеют объектный тип. Речь идёт о функциях, массивах, о том, что мы называем «объектами», и о многих других сущностях. В основе всех этих типов данных лежит тип object , и они, хотя и во многом друг от друга отличаются, имеют и много общего.
Выражения
Выражения — это фрагменты кода, которые можно обработать и получить на основе проведённых вычислений некое значение. В JavaScript существует несколько категорий выражений.
Арифметические выражения
В эту категорию попадают выражения, результатом вычисления которых являются числа.
Строковые выражения
Результатом вычисления таких выражений являются строки.
Первичные выражения
В эту категорию попадают литералы, константы, ссылки на идентификаторы.
Сюда же можно отнести и некоторые ключевые слова и конструкции JavaScript.
Выражения инициализации массивов и объектов
Логические выражения
В логических выражениях используются логические операторы, результатом их вычисления оказываются логические значения.
Выражения доступа к свойствам
Эти выражения позволяют обращаться к свойствам и методам объектов.
Выражения создания объектов
Выражения объявления функций
Выражения вызова
Такие выражения используются для вызова функций или методов объектов.
Работа с объектами
Выше мы уже сталкивались с объектами, говоря об объектных литералах, о вызове их методов, о доступе к их свойствам. Здесь мы поговорим об объектах подробнее, в частности, рассмотрим механизм прототипного наследования и использование ключевого слова class .
▍Прототипное наследование
JavaScript выделяется среди современных языков программирования тем, что поддерживает прототипное наследование. Большинство же объектно-ориентированных языков используют модель наследования, основанную на классах.
У каждого JavaScript-объекта есть особое свойство ( __proto__ ), которое указывает на другой объект, являющийся его прототипом. Объект наследует свойства и методы прототипа.
Предположим, у нас имеется объект, созданный с помощью объектного литерала.
Или мы создали объект, воспользовавшись конструктором Object .
В любом из этих случаев прототипом объекта car будет Object.prototype .
Если создать массив, который тоже является объектом, его прототипом будет объект Array.prototype .
Проверить это можно следующим образом.
Здесь мы пользовались свойством __proto__ , оно не обязательно должно быть доступно разработчику, но обычно обращаться к нему можно. Надо отметить, что более надёжным способом получить прототип объекта является использование метода getPrototypeOf() глобального объекта Object .
Все свойства и методы прототипа доступны объекту, имеющему этот прототип. Вот, например, как выглядит их список для массива.
Подсказка по массиву
Базовым прототипом для всех объектов является Object.prototype .
У Object.prototype прототипа нет.
То, что мы видели выше, является примером цепочки прототипов.
При попытке обращения к свойству или методу объекта, если такого свойства или метода у самого объекта нет, их поиск выполняется в его прототипе, потом — в прототипе прототипа, и так — до тех пор, пока искомое будет найдено, или до тех пор, пока цепочка прототипов не кончится.
Помимо создания объектов с использованием оператора new и применения объектных литералов или литералов массивов, создать экземпляр объекта можно с помощью метода Object.create() . Первый аргумент, передаваемый этому методу, представляет собой объект, который станет прототипом создаваемого с его помощью объекта.
Проверить, входит ли некий объект в цепочку прототипов другого объекта, можно с использованием метода isPrototypeOf() .
Функции-конструкторы
Выше мы создавали новые объекты, пользуясь уже имеющимися в языке функциями-конструкторами (при их вызове используется ключевое слово new ). Такие функции можно создавать и самостоятельно. Рассмотрим пример.
Здесь мы создаём функцию-конструктор. При её вызове создаётся новый объект, на который указывает ключевое слово this в теле конструктора. Мы добавляем в этот объект свойство name и записываем в него то, что передано конструктору. Этот объект возвращается из конструктора автоматически. С помощью функции-конструктора можно создать множество объектов, свойства name которых будут содержать то, что передано при их создании конструктору.
После создания конструктора мы добавляем в его прототип функцию, которая будет выводить в консоль значение свойства name объекта, созданного с помощью этой функции. Все объекты, созданные с помощью этого конструктора, будут иметь один и тот же прототип, а значит и пользоваться одной и той же функцией hello() . Это несложно проверить, создав ещё один объект типа Person и сравнив его функцию hello() с функцией уже имеющегося в примере объекта (имя функции в таком случае записывают без скобок).
▍Классы
В стандарте ES6 в JavaScript пришло такое понятие как «класс».
До этого в JavaScript можно было пользоваться лишь вышеописанным механизмом прототипного наследования. Этот механизм непривычно выглядел для программистов, пришедших в JS из других языков. Поэтому в языке и появились классы, которые, по сути, являются «синтаксическим сахаром» для прототипного механизма наследования. То есть, и объекты, созданные традиционным способом, и объекты, созданные с использованием классов, имеют прототипы.
Объявление класса
Вот как выглядит объявление класса.
У класса есть идентификатор, который можно использовать для создания новых объектов с применением конструкции new ClassIdentifier() .
При создании нового объекта вызывается метод constructor , ему передаются параметры.
В классе можно объявлять методы. В нашем случае hello() — это метод, который могут вызывать все объекты, созданные на основе класса. Вот как выглядит создание нового объекта с использованием класса Person .
Наследование, основанное на классах
Классы могут расширять другие классы. Объекты, созданные на основе таких классов, будут наследовать и методы исходного класса, и методы, заданные в расширенном классе.
Если класс, расширяющий другой класс (наследник этого класса) имеет метод, имя которого совпадает с тем, который есть у класса-родителя, этот метод имеет преимущество перед исходным.
При вызове метода hello() в вышеприведённом примере будет возвращена строка Hello, I am Flavio. I am a programmer .
В классах не предусмотрено наличие переменных (свойств), свойства создаваемых с помощью классов объектов нужно настраивать в конструкторе.
Внутри класса можно обращаться к родительскому классу с использованием ключевого слова super .
Статические методы
Методы, описываемые в классе, можно вызывать, обращаясь к объектам, созданным на основе этого класса, но не к самому классу. Статические ( static ) методы можно вызывать, обращаясь непосредственно к классу.
Приватные методы
В JavaScript нет встроенного механизма, который позволяет объявлять приватные (частные, закрытые) методы. Это ограничение можно обойти, например, с использованием замыканий.
Геттеры и сеттеры
В классе можно описывать методы, предваряя их ключевыми словами get или set . Это позволяет создавать так называемые геттеры и сеттеры — функции, которые используются для управления доступом к свойствам объектов, созданных на основе класса. Геттер вызывается при попытке чтения значения псевдо-свойства, а сеттер — при попытке записи в него нового значения.
Итоги
В этом материале мы поговорили о переменных, о типах данных, о выражениях и о работе с объектами в JavaScript. Темой нашего следующего материала будут функции.
Уважаемые читатели! Если вы уже давно пишете на JS, просим рассказать о том, как вы относитесь к появлению в языке ключевого слова class.
Простые (примитивные) типы данных
Переменная — это область памяти, которой присвоено какое-либо имя и которая хранит значение определенного типа. Соответственно, у переменной есть тип, имя и значение. Тип определяет диапазон хранимых в памяти значений, размер переменной, а также операции, которые можно над ней производить.
Перед тем как использовать переменную, необходимо ее объявить и инициализировать (то есть присвоить ей какое-либо значение). Можно сделать это по отдельности, либо одновременно.
Посмотрим, как это происходит на практике:
Здесь в первой строке мы объявляем переменную, а во второй — инициализируем ее.
А здесь переменная инициализируется одновременно с объявлением.
Компилятор предоставляет нам возможность объявить и инициализировать несколько переменных в строку, через запятую, однако такое написание не рекомендуется в CodeStyle Java, так как это снижает читаемость кода.
Имя переменной должно соответствовать определенным требованиям:
— оно не должно являться ключевым словом (то есть именем не могут быть, к примеру, слова float, return и т.д.)
— имя может содержать любые символы, кроме знаков пунктуации и пробелов, а так же не может начинаться с цифры — так, имена put_the_Bag, putTheBag, putTheBag7 возможны, а 7putTheBag или put,TheBag — нет. Обратите также внимание, что имя переменной в соответствии с CodeStyle, всегда начинается с маленькой буквы, в противном случае ее будет невозможно отличить от класса. который, наоборот, именуется только с большой буквы.
Следует отметить, что если имя переменной состоит из нескольких слов, уместно писать первое слово с маленькой буквы, а остальные слова — с большой. Это — так называемый CamelStyle (сравните внешний вид такого имени и вид горбов у верблюда).
Кроме того, нельзя забывать, что переменные number и, к примеру, numBER — это две разные переменные. Так происходит из-за того, что язык Java чувствителен к регистру.
Теперь вернемся к тому, что каждая переменная имеет определенный тип. Для этого выясним, какие типы данных вообще существуют в Java?
Типы данных бывают примитивными и ссылочными. К примитивным относят следующие 8 типов:
— логический тип ***boolean***
— целочисленные типы ***byte***, ***short***, ***int***, ***long***
— вещественные типы ***float*** и ***double***
— символьный тип ***char***.
Рассмотрим подробнее каждый из них.
Логический тип ***boolean*** обычно занимает 32 бита, однако точно не определен и может отличаться на разных JDK. Тип boolean хранит всего 2 вида значений — true и false (по умолчанию он изначально false).
Целочисленный тип ***byte*** имеет диапазон от -128 до 127 и занимает 8 бит.
Тип ***short*** хранит целые числа в диапазоне от -32768 до 32767 и занимает 16 бит.
Диапазон типа ***int*** — от -2147483648 до 2147483647, а для хранения переменной этого типа задействовано 32 бита.
Последний из целочисленных типов, тип ***long*** занимает 64 бита и хранит числа в диапазоне от –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807. Чтобы обозначить принадлежность переменной к данному типу, можно добавить в конце числа букву “*l* “(или “*L*”).
Переменные целочисленных типов могут быть инициализированы в виде десятичных, восьмеричных и шестнадцатеричных значений. Восьмеричная запись выглядит следующим образом: число начинается с 0, а затем следуют одна или несколько восьмеричных цифр (например 0475).
Для шестнадцатеричной записи используются приставки “0x” или “OX”, за которой идут числа от 0 до 9, буквы от “а” до “f” или от “A “ до “F” (пример записи — 0x65C).
Беззнаковый тип char используется для хранения различных символов и реализован с использованием стандарта UNICODE. Размер этого типа — 16 бит.
При инициализации символьное значение типа char заключается в одиночные кавычки. Кроме того, возможна запись при помощи числа — то есть номера символа в таблице UNICODE. Третья форма записи — это использование кода символа в этой таблице, состоящего из приставки “\u” и шестнадцатеричного числа. Посмотрим, как будет записана, к примеру, буква “p” каждым из этих способов:
Типы **float** и **double** занимают 32 и 64 бита соответственно. Они отличаются от остальных примитивов тем, что являются числами с плавающей точкой. Их отличительной особенностью является то, что они имеют точность, например, число 1/3 представить полностью в десятичной системе невозможно, лучшее, что мы можем получить — число 0,3333…
Для отображения такого числа используются два коэффициента к мантиссе и экспоненте, которые обозначают действующую часть и ее сдвиг относительно нуля на порядки.
Явные и неявные приведения
Примитивы могут преобразовываться между собой явно ( когда мы в скобках указываем тип, к которому хотим привести) и неявно ( это приведение делает компилятор самостоятельно).
Причин для явного приведения несколько, но они сводятся к тому, происходит ли потеря информации.
Далее приведу случаи явных приведений:
— Приводимое число имеет больший диапазон, например long в int
— Число теряет дробную часть, например double в int
— Число теряет точность, например double во float
— Число теряет информацию о знаке. byte в беззнаковый char.
Программисту в таких случаях требуется проследить за тем, что не произойдет потери важной информации.