Базовый CS с нуля
Переменная — это именованная ячейка
Ты уже знаешь, что память — длинный ряд пронумерованных ячеек, каждая из которых хранит значение по фиксированному адресу. CPU читает и записывает эти ячейки по номеру: «дай ячейку 1042», «запиши 255 в ячейку 1042». Для машины это работает идеально — но для программиста это изнурительно.
Представь программу, которая отслеживает счёт игрока. Тебе пришлось бы помнить, что «счёт живёт по адресу 1042», и не перепутать с «количеством игроков по адресу 1080». Одна ошибка — один неверный адрес — и ты читаешь не ту ячейку. Программы, написанные таким образом, хрупки и почти невозможны для понимания.
Каждый язык программирования решает эту проблему одинаково: он позволяет прикрепить
имя к ячейке памяти. Вместо «адрес 1042» ты пишешь score. Имя устойчиво и
читаемо; адресом управляет система за тебя. Эта именованная ячейка и есть переменная.
Эта единственная идея — человекочитаемое имя, привязанное к ячейке — лежит в основе всего, что связано с хранением данных в программах.
После этого урока ты сможешь объяснить, что такое переменная, в понятиях ячейки памяти и имени, отличить имя от хранящегося в нём значения и описать, что происходит при объявлении переменной.
Проблема: сырые адреса неуправляемы. На языке машины каждое чтение и запись используют числовой адрес. Адрес 1042 ничего не говорит человеку без отдельной заметки «там хранится счёт». По мере роста программы до десятков значений поддержание этих заметок в актуальном состоянии становится единственной работой программиста — и ошибки неизбежны.
Языки программирования высокого уровня были изобретены отчасти именно для того, чтобы освободить программистов от ручного отслеживания числовых адресов. Они вводят понятие переменной: именованного места в памяти.
Что такое переменная: имя, привязанное к ячейке. Переменная — это сочетание двух разных вещей:
- Имя — человекочитаемая метка:
score,playerCount,temperature. Имя существует только в исходном коде. Для CPU оно не имеет смысла. - Ячейка памяти (или непрерывная группа ячеек) — фактическое физическое место в RAM, где хранится значение. CPU работает с адресом этой ячейки.
Слово привязка (binding) описывает связь между именем и ячейкой. Когда переменная
score привязана к ячейке с адресом 1042, написание score в коде означает «ячейка
по адресу 1042». Привязку поддерживает среда выполнения (runtime) — программа,
исполняющая твой код: встречая имя score, она ищет адрес и обращается к нему.
Думай о привязке как о стикере на физической коробке. Стикер («score») — то, что ты читаешь; коробка — место, где значение реально хранится. Содержимое коробки можно менять, но стикер остаётся на той же коробке.
Объявление переменной: резервирование ячейки и присвоение имени. Прежде чем
использовать переменную, её нужно объявить. Объявление — это инструкция,
которая сообщает среде выполнения: «зарезервируй ячейку памяти и с этого момента
пусть имя score ссылается на неё».
В TypeScript (и JavaScript) переменная объявляется с помощью let или const:
let score = 0;Что происходит на машинном уровне:
- Среда выполнения находит свободную ячейку памяти (например, по адресу 1042).
- Она записывает привязку: имя
score→ адрес 1042. - В эту ячейку записывается начальное значение
0.
После объявления каждое использование имени score в коде транслируется средой
выполнения в чтение или запись по адресу 1042. Ты никогда не видишь адрес — только имя.
Почему это работает
Почему их называют «переменными»? Слово пришло из математики, где переменная — символ,
который может принимать разные значения (как x в уравнении). В программировании идея та
же: имя score может «варьироваться» — ты можешь менять значение, хранящееся в ячейке,
со временем. Математический термин был заимствован при создании ранних языков
программирования и закрепился.
Имя и значение — разные вещи. Это самое важное различие в этом уроке:
- Имя (
score) — это метка. Оно фиксировано с момента объявления. Нельзя изменить имя в середине программы. - Значение (сейчас
0) — содержимое ячейки. Оно может меняться много раз.
Это два принципиально разных объекта. score и 0 — не одно и то же. score —
идентификатор, слово в исходном коде. 0 — значение, паттерн битов в ячейке. Когда ты
пишешь score, среда выполнения подставляет текущее содержимое ячейки — но само имя
нигде в этой ячейке не хранится.
Подумай: после объявления let score = 0, если программа позже вычислит новый счёт,
имя score по-прежнему ссылается на ту же ячейку по адресу 1042, но содержимое ячейки
может стать 42. Имя не изменилось; изменилось значение в ячейке.
Частая ошибка
Распространённая путаница: думать, что переменная и есть значение. Это не так. Переменная — именованная ячейка. Значение — то, что в ней сейчас содержится. Думай о переменной как о контейнере, а о значении — как о его текущем содержимом. Контейнер сохраняется даже тогда, когда содержимое меняется. Это разграничение становится критически важным при изучении присваивания (следующий урок) и мутации.
Задача среды выполнения: таблица имя→адрес. При выполнении программы среда выполнения поддерживает внутреннюю таблицу, отображающую каждое живое имя переменной на её адрес в памяти. В теории языков эта таблица иногда называется таблицей символов или окружением.
Каждый раз, когда программа обращается к score, среда выполнения смотрит в таблицу:
- «score» → адрес 1042 → читает ячейку 1042 → возвращает хранящееся значение.
Когда программа пишет score = 42, среда выполнения:
- «score» → адрес 1042 → записывает 42 в ячейку 1042.
С твоей точки зрения программиста, имена — первичны. С точки зрения CPU — существуют только адреса. Среда выполнения переводит между двумя мирами.
Разбор объявления шаг за шагом.
let score = 0;
let lives = 3;Объявление score:
- Среда выполнения находит свободную ячейку. Пусть это адрес 1042.
- Привязка записана:
score→ 1042. - Начальное значение
0записывается по адресу 1042.
Состояние: адрес 1042 содержит 0, имя score ссылается на него.
Объявление lives:
- Среда выполнения находит ещё одну свободную ячейку. Пусть это адрес 1045.
- Привязка записана:
lives→ 1045. - Начальное значение
3записывается по адресу 1045.
Состояние: адрес 1045 содержит 3, имя lives ссылается на него.
Чтение score позже в программе:
- Среда выполнения ищет
score→ адрес 1042. - Читает адрес 1042 и возвращает
0.
Программист пишет score и думает «текущий счёт». CPU читает адрес 1042 и не думает
ничего — он просто возвращает биты. Среда выполнения переводит один мир в другой.
Переменная 'count' привязана к адресу 200. Ячейка по адресу 200 содержит значение 7. Сколько ячеек памяти напрямую занимает переменная 'count'? Введи число.
После 'let x = 5' переменная x привязана к адресу 300. Позже программа записывает новое значение 9 в эту ячейку. К какому адресу теперь привязана x?
Программа объявляет 'let a = 10' и 'let b = 20'. Она читает a. Какое значение получает?
Память содержит ячейки по адресам от 0 до 999. Программа объявляет 3 переменные. Сколько именованных привязок существует после объявлений?
Верно или нет (1=верно, 0=нет): имя переменной хранится внутри ячейки памяти, которая содержит её значение.
В чём разница между именем переменной и её значением?
Переменная — человекочитаемое имя, постоянно привязанное к ячейке памяти (или группе ячеек). Имя — метка в исходном коде: оно не меняется и не хранится в самой ячейке. Значение — паттерн битов, который ячейка хранит в данный момент; оно может меняться в любой момент. Объявление переменной резервирует ячейку и записывает привязку имя→адрес во внутреннюю таблицу среды выполнения. Каждое обращение к имени в коде транслируется средой выполнения в чтение или запись по адресу ячейки. CPU видит только адреса; имя существует для удобства программиста и управляется средой выполнения.