Область видимости и подъем переменных в JavaScript для инженеров по автоматизации тестирования
Часть 8 для учащихся, изучающих QA: глобальный, функциональный и блочный области видимости; var против let против const; подъем переменных; временная зона мертвых значений; а также то, как эти правила предотвращают утечку данных тестов.
Источники: JavaScript For QA Engineers: My Learning Journey — Part 8
Иногда JavaScript не работает не из-за ошибочной логики, а потому, что переменная отсутствует там, где ожидалось её нахождение.
Что было рассказано до сих пор
Типичный путь изучения JavaScript для автоматизации тестирования начинается с выбора языка, затем рассматриваются переменные, типы данных, массивы, объекты, операторы, циклы и функции. Концепции области видимости и подъема переменных объясняют, почему значение работает в одном месте, но вызывает ошибку в другом, а также почему движок кажется «видящим» объявления до той строки, в которой они записаны.
Что такое область видимости?
Область видимости отвечает на простой вопрос: где видна эта переменная или функция?
let browser = "Chrome";
console.log(browser);
//Output: Chrome
Здесь browser доступен в области видимости, где он был объявлен.
Вместо этого объявите его внутри функции:
function runTest() {
let browser = "Chrome";
console.log(browser);
}
runTest();
Теперь browser существует только внутри этой функции. Попытка обратиться к нему снаружи приведет к ошибке:
console.log(browser);
они выбрасываются, поскольку имя принадлежит области видимости функции. Именно из-за этой разницы важны типы областей видимости в коде тестов.
Типы областей видимости в JavaScript
Наиболее часто встречающиеся формы областей видимости в автоматизации — это:
- Глобальная область видимости
- Область видимости функции
- Блочная область видимости
- Лексическая область видимости
1. Глобальная область видимости
Переменные, объявленные вне любых функций и блоков, находятся в глобальной области видимости.
const environment = "staging";
function runTest() {
console.log(`Running on: ${environment}`); // Works ✅
}
runTest();
console.log(environment); // Works ✅
Глобальные переменные подходят для хранения общих значений, таких как базовые URL-адреса, имена среды и конфигурация. Используйте их осторожно: когда множество вспомогательных функций изменяют одну и ту же глобальную переменную, становится сложно выявить причины сбоев.
2. Область видимости функции
Имена, объявленные внутри функции, как правило, видны только внутри нее.
function login() {
const password = "Admin@123";
console.log(`Logging in with: ${password}`); // Works ✅
}
login();
console.log(password); // ❌ Error — password is not defined
Благодаря такой изоляции учетные данные и данные, связанные с конкретным тестом, не могут утекнуть или быть перезаписаны нерелевантными вспомогательными функциями.
Простой способ запомнить
Объявление внутри функции → доступно только внутри этой функции.
Вспомогательные элементы для входа в систему или навигации, которые можно использовать несколько раз, опираются на этот принцип ограничения области видимости.
3. Область видимости блока
Блоком считается любой участок кода между { }. С помощью ключевых слов let или const имя, объявленное внутри блока, доступно только внутри этого блока.
if (true) {
let browser = "Chrome";
console.log(browser);
}
//Output:Chrome
Доступ вне блока:
console.log(browser);
невозможен, поскольку let и const имеют область видимости блока. Это свойство важно при использовании условий и циклов в тестах.
Пример с циклом
for (let i = 1; i <= 3; i++) {
console.log(i);
}
//Output:
1
2
3
Значения, объявленные с помощью let в каждой итерации цикла, остаются внутри блока данной итерации, что предотвращает проблемы, связанные с общим использованием переменной var при добавлении асинхронных обработчиков в циклах.
var против let против const и область видимости
var имеет область видимости на уровне функции (или глобальную, если объявлен вне функции). let и const имеют область видимости на уровне блока. В качестве стандарта предпочитайте const, используйте let, когда требуется переопределение, и избегайте новых объявлений var в современном тестовом коде. В крупных проектах на Playwright или Cypress одно это правило устраняет целый класс проблем типа «работает на моем компьютере», когда один тест перезаписывает состояние другого через общую переменную var с областью видимости на уровне функции.
if (true) {
var browser = "Chrome";
let version = "Latest";
const environment = "QA";
}
console.log(browser);
//Output:Chrome
console.log(version);
console.log(environment);
const baseURL = "https://myapp.com"; // Global — shared everywhere
Что такое подъем объявлений?
Подъем объявлений — это привычка движка обрабатывать объявления до выполнения их тела сверху вниз. Объявления регистрируются заранее, но присваивания происходят только тогда, когда выполняется соответствующая строка кода.
Подъем объявлений с var
function loginTest() {
const username = "admin"; // Function scope — only here
const password = "Admin@123"; // Function scope — only here if (username === "admin") {
let accessLevel = "full"; // Block scope — only in this if block
console.log(`Access: ${accessLevel}`);
} console.log(`${baseURL}/login`); // Global still accessible ✅
}
Имя var существует с момента начала функции/глобального области видимости (инициализировано как undefined) до момента выполнения строки присваивания.
Подъем переменных с использованием let
let browser = "Chrome";
function runTest() {
console.log(browser);
}
runTest();
//Output:Chrome
let также регистрируется заранее, но его нельзя читать до строки объявления. Эта промежуток времени называется временной мертвой зоной.
Что такое временная мертвая зона?
Временная мертвая зона — это период с момента входа в область видимости до выполнения объявления let/const. Попытка обратиться к переменной в этот период приводит к ошибке, а не к возврату значения undefined.
let environment = "QA";
function runTest() {
let browser = "Chrome";
if (true) {
let testName = "Login Test";
console.log(environment);
console.log(browser);
console.log(testName);
}
}
runTest();
Простой способ запомнить
Ранний доступ к
var→undefined. Ранний доступ кlet/const→ ошибка (временная мертвая зона).
Подъем переменных с использованием объявлений функций
Объявления функций полностью поднимаются вверх: их можно вызывать до момента их появления в файле.
console.log(browser);
var browser = "Chrome";
// Output:undefined
Выражение функции и поднятие
Выражения функций, присваиваемые переменным типа const/let, подчиняются правилам переменных: связь с ними существует в зоне доступа до момента присвоения.
var browser;
console.log(browser);
browser = "Chrome";
Объявление функции
undefined
Полезно для вспомогательных функций, которые нужно можно вызывать в любой точке области видимости после её начала.
Выражение функции
console.log(browser);
let browser = "Chrome";
Более безопасно, когда необходимо контролировать момент появления значения функции, часто с использованием const.
Пример автоматизации тестирования
Ошибки области видимости явно проявляются в коде объектов страниц и фикстчеров.
ReferenceError
{
console.log(testName);
let testName = "Login Test";
}
Хранение селекторов и учетных данных внутри функций или блоков, к которым они относятся, предотвращает заражение между тестами.
Почему область видимости важна в автоматизации
Общие изменяемые глобальные переменные делают параллельные или случайно перестроенные тесты ненадежными. Область видимости функций и блоков сохраняет данные каждого теста в локальной области. Лексическая область видимости позволяет вложенным вспомогательным функциям использовать конфигурацию без необходимости повторной передачи всех аргументов.
let testName = "Login Test";
Лексическая область видимости на практике
Внутренние функции видят связанные переменные из внешних областей, где они были определены, а не там, где их вызывают.
ReferenceError
runTest();
function runTest() {
console.log("Test started");
}
//Output:Test started
Именно поэтому кallback, определенный внутри теста, все еще может читать переменные page или user этого теста. Закрытия позволяют фикстурам передавать контекст во вложенные вспомогательные функции без использования глобальных переменных.
Распространенные ошибки
Чтение переменной с ключевым словом let до ее объявления:
runTest();
const runTest = function() {
console.log("Test started");
};
Предположение, что переменная с ключевым словом var имеет область видимости блока внутри оператора if:
ReferenceError
Забывать о том, что цикл с использованием var имеет одну и ту же переменную во всех итерациях:
runTest();
function runTest() {
console.log("Test started");
}
Отладка проблем с областью видимости
Когда ошибка ReferenceError возникает при обращении к переменной, которую вы только что определили, проверьте, какая { } или функция является её владельцем, использовались ли var или let, а также находится ли обращение выше места объявления (зона TDZ).
runTest();
const runTest = function() {
console.log("Test started");
};
Практические правила для наборов тестов
- Для страниц, селекторов и объектов конфигурации предпочитайте
const. - Используйте
letтолько для значений, которые должны меняться. - Избегайте использования новых переменных с
var. - Храните конфиденциальную информацию внутри области видимости функции.
- Не полагайтесь на случайные глобальные переменные, возникающие из-за отсутствия объявлений.
const browser = "Chrome";
function runTest() {
const testName = "Login Test";
console.log(`Running ${testName}`);
console.log(`Browser: ${browser}`);
}
runTest();
//Output:
Running Login Test
Browser: Chrome
let testStatus = "Passed";
function testOne() {
testStatus = "Failed";
}
function testTwo() {
console.log(testStatus);
}
Краткая модель понимания
Область видимости — это место, где имя является доступным. Подъем — это момент, когда происходит регистрация объявления. Запретная зона — это область до инициализации с помощью let/const.
const testCases = ["Login", "Search", "Checkout"];
function executeTests() {
for (const testCase of testCases) {
console.log(`Executing: ${testCase}`);
}
}
executeTests();
//Output:
Executing: Login
Executing: Search
Executing: Checkout
Собирание всего вместе в небольшом помощнике для тестов
let username;
let password;
let browser;
let testStatus;
function login() {
const username = "qa_user";
const password = "Password@123"; console.log(`Logging in as ${username}`);}
Благодаря этим заменителям локальные переменные помощника остаются внутри него, настройки уровня сборки сохраняют свою целесообразность, а ошибки раннего доступа становятся понятными вместо того, чтобы оставаться загадкой. Область видимости и подъем перестают быть тривиальными вопросами и превращаются в повседневные инструменты для стабильной автоматизации JavaScript.
Цепочки областей видимости во время асинхронных шагов тестирования
Автоматизация редко работает синхронно. Когда тест с модификатором async ожидает нажатия кнопки, а затем считывает значение переменной, привязка к этой переменной происходит из лексического области видимости, где была определена функция. Механизм подъема объявлений не перемещает операции присваивания мимо точек await; он влияет лишь на то, как объявления регистрируются в момент начала выполнения тела функции. Хранение данных фикстуров в переменных типа const в начале функции теста позволяет легче следить за структурой кода при разборе стека вызовов после истечения таймаута.
Почему ошибки TDZ кажутся строгими — и почему они полезны
Встреча с ошибкой типа ReferenceError вместо значения undefined может удивить разработчиков, привыкших к использованию переменных с модификатором var. В наборе тестов такая строгость полезна: ошибка возникает быстро, если вспомогательная функция помещается выше своего объявления с модификатором let. Считайте ошибки TDZ нарушениями порядка выполнения кода в файле тестов, а не непостоянным поведением продукта.
Миграция старых наборов var
При обновлении устаревших скриптов автоматизации постепенно заменяйте var на const или let, запускайте набор тестов и проверяйте наличие проблем с областью видимости внутри тел операторов if/for, которые ранее приводили к утечкам. Сопровождайте процесс миграции правилами линт-проверки, запрещающими использование var, чтобы новые тесты не вновь не привели к утечкам на уровне всей функции.
Эффект теневого объявления в вложенных помощниках
Внутренняя переменная const browser = „Firefox“, находящаяся внутри вспомогательной функции, скрывает внешнюю переменную browser на протяжении всего времени выполнения этого блока. Это явление называется лексическим затенением, а не подъёмом переменных. В объектах страниц затенение может привести к тому, что тест будет использовать неверный базовый URL, если вложенная вспомогательная функция переопределяет уже существующее имя. При вложении функций предпочтительно использовать уникальные имена (overrideBrowser, tempBrowser) или передавать значения в качестве параметров, вместо того чтобы использовать один и тот же идентификатор снова.