Главные различия: **область видимости** и **hoisting**. var имеет функциональную область видимости и поднимается с инициализацией undefined. let и const имеют блочную область видимости и тоже поднимаются, но остаются в "Temporal Dead Zone" (TDZ) до строки объявления — обращение к ним до объявления выбрасывает ReferenceError. const запрещает переприсваивание, но не мутацию объектов. Современный стандарт: используй const по умолчанию, let когда нужно переприсваивание, var не используй.
// var — ФУНКЦИОНАЛЬНАЯ область видимости
function example() {
if (true) {
var x = 10 // видна во всей функции, не только в if-блоке
}
console.log(x) // 10 — работает!
}
// let/const — БЛОЧНАЯ область видимости
function example2() {
if (true) {
let y = 20 // видна только внутри {}
const z = 30 // тоже только внутри {}
}
console.log(y) // ReferenceError: y is not defined
}Блок — это любые фигурные скобки: if, for, while, функция, просто {}.
JavaScript **перед выполнением** сканирует код и "поднимает" объявления переменных и функций наверх их области видимости.
var — поднимается и инициализируется как undefined:
console.log(a) // undefined (не ошибка!)
var a = 5
console.log(a) // 5
// JS видит это так:
var a = undefined // поднято наверх
console.log(a) // undefined
a = 5 // присваивание остаётся на месте
console.log(a) // 5let/const — поднимаются, но остаются в TDZ (Temporal Dead Zone):
console.log(b) // ReferenceError: Cannot access 'b' before initialization
let b = 5
// let/const ПОДНИМАЮТСЯ (движок о них знает), но к ним нельзя обращаться
// до строки объявления. Зона от начала блока до объявления = TDZ.TDZ — почему это важно:
// Пример TDZ в действии
{
// ← здесь начинается TDZ для 'value'
console.log(value) // ReferenceError! (TDZ)
// ← здесь заканчивается TDZ
let value = 42
console.log(value) // 42
}Функции-объявления (function declaration) поднимаются **целиком** — их можно вызывать до объявления:
greet() // "Привет!" — работает!
function greet() {
console.log('Привет!')
}
// Но function expression (через var/let/const) — НЕ поднимается
hello() // TypeError: hello is not a function
var hello = function() { console.log('Hello') }const num = 42
num = 100 // TypeError: Assignment to constant variable
const obj = { name: 'Alice' }
obj.name = 'Bob' // OK! — мутация разрешена
obj.age = 25 // OK! — добавление свойства разрешено
obj = { name: 'Eve' } // TypeError — переприсваивание запрещено
const arr = [1, 2, 3]
arr.push(4) // OK! — [1, 2, 3, 4]
arr[0] = 99 // OK! — [99, 2, 3, 4]
arr = [] // TypeErrorДля полной неизменяемости объекта используй Object.freeze().
// var: все итерации делят ОДНУ переменную i
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0) // 3, 3, 3
}
// let: каждая итерация имеет СВОЮ переменную i
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0) // 0, 1, 2
}const — по умолчанию для всего
↓ только если нужно переприсваивание
let — для счётчиков циклов, аккумуляторов, флагов
↓ никогда
var — устарел, не использовать в современном кодеПравило: начинай с const, переходи на let только при необходимости.
var let const
Scope function block block
Hoisting да (undef) да (TDZ) да (TDZ)
Переприсв. да да нет
Мутация да да да
Повторное да нет нет
объявление**Структурируй ответ** по трём критериям: область видимости → hoisting → переприсваивание.
**Обязательно упомяни TDZ**: многие кандидаты говорят "let не поднимается" — это неточно. Правильно: "поднимается, но находится в TDZ — обращение до объявления выбрасывает ReferenceError, а не возвращает undefined как var".
**Покажи практику**: назови конкретные последствия — баг с var в цикле, function declaration vs expression.
**Время ответа**: 2-3 минуты.
1. **"let и const не поднимаются"** — технически неверно. Они поднимаются, но остаются в TDZ. Это путаница, которая выдаёт поверхностное знание.
2. **"const делает объект неизменяемым"** — нет! const запрещает только переприсваивание. Свойства объекта можно менять. Для заморозки нужен Object.freeze().
3. **Не знать про var в цикле** — если используешь var в современном коде или не знаешь о проблеме замыкания — это красный флаг для любого JS-разработчика.
Демонстрация hoisting, TDZ, scope различий и поведения const с объектами
// ===== 1. HOISTING =====
console.log('=== Hoisting ===')
// var: поднимается и инициализируется как undefined
console.log('var до объявления:', typeof varVariable) // "undefined" (не ошибка!)
var varVariable = 'привет'
console.log('var после объявления:', varVariable) // "привет"
// let: поднимается, но TDZ — нельзя читать до объявления
try {
console.log(letVariable) // ReferenceError
} catch(e) {
console.log('let до объявления:', e.constructor.name + ': ' + e.message)
}
let letVariable = 'мир'
console.log('let после объявления:', letVariable) // "мир"
// ===== 2. ОБЛАСТЬ ВИДИМОСТИ =====
console.log('\n=== Scope ===')
function scopeDemo() {
var funcScoped = 'я в функции'
if (true) {
var funcScoped2 = 'я тоже в функции (var)'
let blockScoped = 'я только в блоке (let)'
const alsoBlock = 'я только в блоке (const)'
console.log('Внутри блока, funcScoped:', funcScoped) // работает
console.log('Внутри блока, blockScoped:', blockScoped) // работает
}
console.log('Вне блока, funcScoped:', funcScoped) // работает (var)
console.log('Вне блока, funcScoped2:', funcScoped2) // работает (var)
try {
console.log(blockScoped) // ReferenceError
} catch(e) {
console.log('let вне блока:', e.constructor.name) // ReferenceError
}
}
scopeDemo()
// ===== 3. HOISTING ФУНКЦИЙ =====
console.log('\n=== Function Hoisting ===')
// Function declaration — поднимается целиком
console.log('Вызов до объявления:', add(2, 3)) // 5 — работает!
function add(a, b) {
return a + b
}
// Function expression — НЕ поднимается как функция
try {
subtract(5, 2) // TypeError или ReferenceError
} catch(e) {
console.log('Expression до объявления:', e.constructor.name)
}
const subtract = (a, b) => a - b
// ===== 4. CONST И МУТАЦИЯ =====
console.log('\n=== const и мутация ===')
const config = {
host: 'localhost',
port: 3000,
options: { debug: false }
}
// Мутация разрешена!
config.port = 8080
config.options.debug = true
config.newField = 'добавили'
console.log('config после мутации:', config)
// Переприсваивание запрещено
try {
config = {} // TypeError
} catch(e) {
console.log('Переприсваивание const:', e.constructor.name) // TypeError
}
// Для настоящей заморозки
const frozen = Object.freeze({ x: 1, y: 2 })
frozen.x = 99 // молча проигнорируется (в strict mode — ошибка)
console.log('frozen.x после попытки изменить:', frozen.x) // 1
// ===== 5. VAR В ЦИКЛЕ =====
console.log('\n=== var vs let в цикле ===')
const varCallbacks = []
for (var i = 0; i < 3; i++) {
varCallbacks.push(() => i)
}
console.log('var:', varCallbacks.map(f => f())) // [3, 3, 3]
const letCallbacks = []
for (let j = 0; j < 3; j++) {
letCallbacks.push(() => j)
}
console.log('let:', letCallbacks.map(f => f())) // [0, 1, 2]Главные различия: **область видимости** и **hoisting**. var имеет функциональную область видимости и поднимается с инициализацией undefined. let и const имеют блочную область видимости и тоже поднимаются, но остаются в "Temporal Dead Zone" (TDZ) до строки объявления — обращение к ним до объявления выбрасывает ReferenceError. const запрещает переприсваивание, но не мутацию объектов. Современный стандарт: используй const по умолчанию, let когда нужно переприсваивание, var не используй.
// var — ФУНКЦИОНАЛЬНАЯ область видимости
function example() {
if (true) {
var x = 10 // видна во всей функции, не только в if-блоке
}
console.log(x) // 10 — работает!
}
// let/const — БЛОЧНАЯ область видимости
function example2() {
if (true) {
let y = 20 // видна только внутри {}
const z = 30 // тоже только внутри {}
}
console.log(y) // ReferenceError: y is not defined
}Блок — это любые фигурные скобки: if, for, while, функция, просто {}.
JavaScript **перед выполнением** сканирует код и "поднимает" объявления переменных и функций наверх их области видимости.
var — поднимается и инициализируется как undefined:
console.log(a) // undefined (не ошибка!)
var a = 5
console.log(a) // 5
// JS видит это так:
var a = undefined // поднято наверх
console.log(a) // undefined
a = 5 // присваивание остаётся на месте
console.log(a) // 5let/const — поднимаются, но остаются в TDZ (Temporal Dead Zone):
console.log(b) // ReferenceError: Cannot access 'b' before initialization
let b = 5
// let/const ПОДНИМАЮТСЯ (движок о них знает), но к ним нельзя обращаться
// до строки объявления. Зона от начала блока до объявления = TDZ.TDZ — почему это важно:
// Пример TDZ в действии
{
// ← здесь начинается TDZ для 'value'
console.log(value) // ReferenceError! (TDZ)
// ← здесь заканчивается TDZ
let value = 42
console.log(value) // 42
}Функции-объявления (function declaration) поднимаются **целиком** — их можно вызывать до объявления:
greet() // "Привет!" — работает!
function greet() {
console.log('Привет!')
}
// Но function expression (через var/let/const) — НЕ поднимается
hello() // TypeError: hello is not a function
var hello = function() { console.log('Hello') }const num = 42
num = 100 // TypeError: Assignment to constant variable
const obj = { name: 'Alice' }
obj.name = 'Bob' // OK! — мутация разрешена
obj.age = 25 // OK! — добавление свойства разрешено
obj = { name: 'Eve' } // TypeError — переприсваивание запрещено
const arr = [1, 2, 3]
arr.push(4) // OK! — [1, 2, 3, 4]
arr[0] = 99 // OK! — [99, 2, 3, 4]
arr = [] // TypeErrorДля полной неизменяемости объекта используй Object.freeze().
// var: все итерации делят ОДНУ переменную i
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0) // 3, 3, 3
}
// let: каждая итерация имеет СВОЮ переменную i
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0) // 0, 1, 2
}const — по умолчанию для всего
↓ только если нужно переприсваивание
let — для счётчиков циклов, аккумуляторов, флагов
↓ никогда
var — устарел, не использовать в современном кодеПравило: начинай с const, переходи на let только при необходимости.
var let const
Scope function block block
Hoisting да (undef) да (TDZ) да (TDZ)
Переприсв. да да нет
Мутация да да да
Повторное да нет нет
объявление**Структурируй ответ** по трём критериям: область видимости → hoisting → переприсваивание.
**Обязательно упомяни TDZ**: многие кандидаты говорят "let не поднимается" — это неточно. Правильно: "поднимается, но находится в TDZ — обращение до объявления выбрасывает ReferenceError, а не возвращает undefined как var".
**Покажи практику**: назови конкретные последствия — баг с var в цикле, function declaration vs expression.
**Время ответа**: 2-3 минуты.
1. **"let и const не поднимаются"** — технически неверно. Они поднимаются, но остаются в TDZ. Это путаница, которая выдаёт поверхностное знание.
2. **"const делает объект неизменяемым"** — нет! const запрещает только переприсваивание. Свойства объекта можно менять. Для заморозки нужен Object.freeze().
3. **Не знать про var в цикле** — если используешь var в современном коде или не знаешь о проблеме замыкания — это красный флаг для любого JS-разработчика.
Демонстрация hoisting, TDZ, scope различий и поведения const с объектами
// ===== 1. HOISTING =====
console.log('=== Hoisting ===')
// var: поднимается и инициализируется как undefined
console.log('var до объявления:', typeof varVariable) // "undefined" (не ошибка!)
var varVariable = 'привет'
console.log('var после объявления:', varVariable) // "привет"
// let: поднимается, но TDZ — нельзя читать до объявления
try {
console.log(letVariable) // ReferenceError
} catch(e) {
console.log('let до объявления:', e.constructor.name + ': ' + e.message)
}
let letVariable = 'мир'
console.log('let после объявления:', letVariable) // "мир"
// ===== 2. ОБЛАСТЬ ВИДИМОСТИ =====
console.log('\n=== Scope ===')
function scopeDemo() {
var funcScoped = 'я в функции'
if (true) {
var funcScoped2 = 'я тоже в функции (var)'
let blockScoped = 'я только в блоке (let)'
const alsoBlock = 'я только в блоке (const)'
console.log('Внутри блока, funcScoped:', funcScoped) // работает
console.log('Внутри блока, blockScoped:', blockScoped) // работает
}
console.log('Вне блока, funcScoped:', funcScoped) // работает (var)
console.log('Вне блока, funcScoped2:', funcScoped2) // работает (var)
try {
console.log(blockScoped) // ReferenceError
} catch(e) {
console.log('let вне блока:', e.constructor.name) // ReferenceError
}
}
scopeDemo()
// ===== 3. HOISTING ФУНКЦИЙ =====
console.log('\n=== Function Hoisting ===')
// Function declaration — поднимается целиком
console.log('Вызов до объявления:', add(2, 3)) // 5 — работает!
function add(a, b) {
return a + b
}
// Function expression — НЕ поднимается как функция
try {
subtract(5, 2) // TypeError или ReferenceError
} catch(e) {
console.log('Expression до объявления:', e.constructor.name)
}
const subtract = (a, b) => a - b
// ===== 4. CONST И МУТАЦИЯ =====
console.log('\n=== const и мутация ===')
const config = {
host: 'localhost',
port: 3000,
options: { debug: false }
}
// Мутация разрешена!
config.port = 8080
config.options.debug = true
config.newField = 'добавили'
console.log('config после мутации:', config)
// Переприсваивание запрещено
try {
config = {} // TypeError
} catch(e) {
console.log('Переприсваивание const:', e.constructor.name) // TypeError
}
// Для настоящей заморозки
const frozen = Object.freeze({ x: 1, y: 2 })
frozen.x = 99 // молча проигнорируется (в strict mode — ошибка)
console.log('frozen.x после попытки изменить:', frozen.x) // 1
// ===== 5. VAR В ЦИКЛЕ =====
console.log('\n=== var vs let в цикле ===')
const varCallbacks = []
for (var i = 0; i < 3; i++) {
varCallbacks.push(() => i)
}
console.log('var:', varCallbacks.map(f => f())) // [3, 3, 3]
const letCallbacks = []
for (let j = 0; j < 3; j++) {
letCallbacks.push(() => j)
}
console.log('let:', letCallbacks.map(f => f())) // [0, 1, 2]Найди и исправь все ошибки, связанные с hoisting и неправильным использованием var/let/const. В коде 5 проблем: 2 с hoisting, 1 с областью видимости var, 1 с const, 1 с var в цикле.
Проблема 1: добавь let total = 0 сразу. Проблема 2: замени var на let внутри if/else. Проблема 3: Object.assign(settings, newSettings) или Object.freeze — нельзя переприсваивать const. Проблема 4: замени var i на let i в цикле. Проблема 5: перемести объявление processA выше вызова или преобразуй в function declaration.
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке