Базовый CS с нуля
Присваивание
Ты объявил переменную. Ты привязал имя к ячейке и записал в неё начальное значение. Что дальше? Программы должны менять значения со временем: счётчики растут, суммы накапливаются, флаги состояний переключаются. Механизм, который меняет значение в ячейке, называется присваиванием.
Присваивание выглядит обманчиво просто: x = 5. Но за этой строкой скрывается
точная машинная операция. Среда выполнения вычисляет правую часть, берёт результат и
записывает его в ячейку, привязанную к имени слева. Старое значение ячейки исчезает.
Всё остальное остаётся неизменным — привязка, имя, адрес — меняется только содержимое
ячейки.
Осознание того, что = в программировании — не знак математического равенства, а
команда записи — это одна из важнейших ранних перестроек мышления при обучении
программированию.
После этого урока ты сможешь объяснить, что делает присваивание на уровне ячейки
памяти, проследить последовательность присваиваний и определить, какое значение
содержит переменная на каждом шаге, а также отличить let (допускает переприсваивание)
от const (одно присваивание).
Присваивание как операция записи. Когда среда выполнения выполняет x = expr,
она производит два шага по порядку:
- Вычисляет выражение в правой части
expr. Это даёт значение — паттерн битов. Выражение может быть литералом (5), именем переменной (y), арифметикой (x + 1) или любым другим вычислимым выражением. - Записывает это значение в ячейку памяти, адрес которой привязан к имени
x. Предыдущее содержимое ячейки перезаписывается и теряется.
Имя в левой части = не вычисляется — оно не читается. Оно преобразуется в адрес, и
этот адрес используется как назначение записи. Вот почему = в коде произносится как
«получает» или «присваивается», а не «равно»: x = 5 означает «x получает 5», а не
«x равно 5».
Первое присваивание и переприсваивание. В жизни переменной есть два различных момента:
- Объявление с начальным значением —
let x = 0;— резервирует ячейку, устанавливает привязку и записывает начальное значение0. Это первое присваивание. - Переприсваивание —
x = 42;— ищет существующую привязку, находит адрес ячейки и записывает новое значение42, перезаписывая0. Привязка не изменяется.
const запрещает переприсваивание. TypeScript и JavaScript также предоставляют
const:
const y = 10;
y = 20; // TypeError: Assignment to constant variable.const означает, что привязка запечатана после первого присваивания — дальнейшие
записи в эту привязку не разрешены. Ячейка записывается ровно один раз. Речь идёт не
о том, что значение «заморожено» в каком-то глубоком смысле (объекты, объявленные как
const, всё ещё могут иметь изменяемые свойства — это рассматривается в уроке 04), а
о том, что привязка имя→ячейка принимает ровно одну запись.
Порядок вычисления важен. Рассмотрим x = x + 1. Правая часть вычисляется
первой: среда выполнения читает текущее значение x, добавляет 1, затем записывает
результат обратно в ту же ячейку. Шаги: (1) читаем x → получаем текущее значение,
(2) добавляем 1, (3) записываем результат в x. Ячейка оказывается на единицу больше.
Старое значение исчезло.
1
// Объявление — резервирует ячейку и записывает начальное значение.
2
let score = 0; // ячейка (допустим, addr 1042) → содержит 0
3
4
// Переприсваивание — перезаписывает содержимое ячейки.
5
score = 10; // addr 1042 → теперь содержит 10
6
score = score + 5; // addr 1042 → читаем 10, добавляем 5, пишем 15
7
score = score * 2; // addr 1042 → читаем 15, умножаем на 2, пишем 30
8
9
// Имя 'score' не изменилось; изменялось только значение в ячейке.
10
console.log(score); // 30
11
12
// const запечатывает привязку после первой записи.
13
const MAX = 100;
14
// MAX = 200; // выбросит TypeError — привязка запечатана
- L2 let: объявляет переменную, резервирует ячейку, записывает начальное значение 0
- L5 Переприсваивание: перезаписывает ячейку. Старое значение 0 потеряно.
- L6 Сначала вычисляется правая часть: читаем score (10), прибавляем 5, результат 15. Затем пишем 15 в ячейку.
- L7 Сначала вычисляется правая часть: читаем score (15), умножаем на 2, результат 30. Затем пишем 30.
- L10 Чтение 'score' возвращает то, что сейчас в ячейке: 30.
- L13 const: первая (и единственная) запись — при объявлении. Привязка теперь запечатана.
- L14 Вторая запись в const-привязку вызывает ошибку во время выполнения.
Проследим каждый шаг: как score меняется от объявления через три переприсваивания.
1
let score = 0;
2
score = 10;
3
score = score + 5;
4
score = score * 2;
5
console.log(score);
Частая ошибка
x = x + 1 выглядит как замкнутый круг — «x это x плюс один?» — но это не уравнение.
Это двухшаговая команда: сначала вычисли x + 1 (читая старое значение), затем
сохрани результат обратно в x. Правая часть вычисляется полностью до того, как
что-либо записывается. После выполнения строки x содержит на единицу больше, чем
раньше. Читать и писать одну и ту же ячейку в одном операторе — совершенно допустимо
и встречается крайне часто.
Граничные случаи
Что происходит при обмене значений двух переменных? Наивный подход:
let a = 1;
let b = 2;
a = b; // a → 2, b всё ещё 2
b = a; // b → 2 (! хотели 1)Проблема: как только выполнилось a = b, исходное значение a (1) потеряно. Решение:
сохранить исходное значение заранее:
let temp = a; // temp → 1, a → 1, b → 2
a = b; // a → 2
b = temp; // b → 1Теперь обе ячейки содержат поменянные значения. Этот классический трёхшаговый обмен — прямое следствие того, что присваивание является деструктивной перезаписью.
let x = 3; x = 7; Какое значение хранит x после второй строки?
let n = 10; n = n + 4; Какое значение хранит n?
let a = 5; let b = a; a = 99; Какое значение хранит b?
let c = 2; c = c * c; c = c * c; Какое значение хранит c?
let x = 1; x = x + x; x = x + x; Какое значение хранит x?
Что именно происходит в памяти при выполнении 'x = x + 1'?
Присваивание — операция записи, состоящая из двух шагов: вычислить выражение
правой части, получив значение, затем записать это значение в ячейку памяти,
привязанную к имени слева. Предыдущее содержимое ячейки перезаписывается и теряется.
Привязка имя→адрес не изменяется. Когда в выражении TypeScript встречается =,
читай его как «получает», а не «равно» — это команда записи, а не математическое
утверждение. let объявляет переменную и допускает последующее переприсваивание.
const выполняет ровно одно присваивание при объявлении и запечатывает привязку от
дальнейших записей. Выражения в правой части, использующие ту же переменную
(x = x + 1), безопасны: правая часть полностью вычисляется до выполнения любой
записи.