Не змінюється глобальна змінна Javascript. JavaScript: Область видимості змінних. Змінні локальні та глобальні

03.04.2021 Поради

останнє оновлення: 05.04.2018

Усі змінні JavaScript мають певну область видимості, в межах якої вони можуть діяти.

Глобальні змінні

Усі змінні, які оголошені поза функціями, є глобальними:

Тут змінні x та d є глобальними. Вони доступні з будь-якого місця програми.

І це змінна z глобальної перестав бути, оскільки вона визначена всередині функції.

Локальні змінні

Змінна, визначена всередині функції, є локальною:

Function displaySquare()( var z = 10; console.log(z); let b = 8; console.log(b); )

Змінні z та b є локальними, вони існують тільки в межах функції. Поза функцією їх не можна використовувати:

Function displaySquare()( var z = 10; console.log(z); ) console.log(z); //помилка, оскільки z не визначено

Коли функція закінчує свою роботу, всі змінні, визначені функції, знищуються.

Приховування змінних

Що якщо у нас є дві змінні – одна глобальна, а інша локальна, які мають однакове ім'я:

Var z = 89; function displaySquare()( var z = 10; console.log(z); // 10 ) displaySquare(); // 10

У цьому випадку функції буде використовуватися та змінна z, яка визначена безпосередньо в функції. Тобто локальна змінна приховає глобальну.

var чи let

При використанні оператора let, кожен блок коду визначає нову область видимості, в якій існує змінна. Наприклад, ми можемо одночасно визначити змінну на рівні блоку та на рівні функції:

Let z = 10; function displayZ()( let z = 20; ( let z = 30; console.log("Block:", z); ) console.log("Function:", z); ) displayZ(); console.log("Global:", z);

Тут усередині функції displayZ визначено блок коду, у якому визначено змінну z. Вона приховує глобальну змінну та змінну z, визначену лише на рівні функції. У реальній програміблок міг надавати вкладену функцію, блок циклу forчи конструкції if. Але в будь-якому випадку такий блок визначає нову область видимості, поза якою змінна не існує.

І в даному випадку ми отримаємо наступний консольний висновок:

Block: 30 Function: 20 Global: 10

За допомогою оператора var ми не можемо визначити одночасно змінну з одним і тим же ім'ям і функції, і в блоці коду цієї функції:

Function displaySquare()( var z = 20; ( var z = 30; // Помилка! Змінна z вже визначена console.log("Block:", z); ) console.log("Function:", z); )

Тобто за допомогою var ми можемо визначити змінну з одним ім'ям або на рівні функції або на рівні блоку коду.

Константи

Все, що стосується оператора let, відноситься і до оператора const, який дозволяє визначити константи. Блоки коду задають область видимості констант, а константи, визначені на вкладених блоках коду, приховують зовнішні константи з тим самим ім'ям:

Const z = 10; function displayZ()( const z = 20; ( const z = 30; console.log("Block:", z); // 30 ) console.log("Function:", z); // 20 ) displayZ( ); console.log("Global:", z); // 10

Неоголошені змінні

Якщо ми не використовуємо це ключове слово при визначенні змінної функції, то така змінна буде глобальною. Наприклад:

Function bar()( foo = "25"; ) bar(); console.log(foo); // 25

Незважаючи на те, що поза функцією bar змінна foo ніде не визначається, проте вона доступна поза функцією у зовнішньому контексті.

Інакше було б якби ми не лише надавали значення змінної, а й визначали б її:

Function bar()( var foo = "25"; ) bar(); console.log(foo); // помилка

strict mode

Визначення глобальних змінних у функціях може призвести до потенційним помилкам. Щоб їх уникнути, використовується строгий режим або strict mode:

"use strict"; function bar()( foo = "25"; ) bar(); console.log(foo);

У цьому випадку ми отримаємо помилку SyntaxError: Unexpected identifier , яка говорить про те, що змінна foo не визначена.

Встановити режим strict mode можна двома способами:

    додати вираз "use strict" на початок коду JavaScript, тоді strict mode буде застосовуватися для всього коду

    додати вираз "use strict" на початок тіла функції, тоді strict mode буде застосовуватись тільки для цієї функції


Продовжуємо вивчати тему функцій у JavaScript. Тут ми торкнемося поняття область видимості змінних. Воно тісно пов'язане з функціями, тому його важливо розуміти.

Слід засвоїти (і розрізняти ці поняття)лише одне, що змінні бувають глобальні і локальні.

Що таке глобальні змінні?Розглянемо приклад...

У цьому прикладі ми створили змінну global, яка є глобальною – тепер ми можемо її використовувати – наприклад, усередині функції, як Ви самі можете переконатись.

У цьому полягає суть глобальних змінних- вони створюються один раз (Скажімо, на початку скрипту, як Ви бачили у прикладі)і потім використовуються в коді програми там, де це необхідно (У масивах, функціях і т.д.).

Що таке локальні змінні?І знову розглянемо приклад...

Цей приклад ілюструє створення локальної змінної local. Вона локальна, оскільки створена всередині функції. І лише всередині неї може використовуватись.

Якщо цю змінну спробувати вивести поза функцією, то у вікні браузера ми нічого не побачимо.

На цих простих прикладахми розглянули поняття область видимості змінниху JavaScript. Ще раз озвучимо його суть: якщо ми створюємо змінну всередині якоїсь функції, то вона є локальною, і працювати з нею ми зможемо лише всередині цієї функції.

А змінні, створені поза функцією, називаються глобальними і можуть використовуватися будь-де, у тому числі і всередині функції.

Змінні

Оголошення змінних

Перш ніж використовувати змінну JavaScript, її необхідно оголосити. Змінні оголошуються за допомогою ключового слова varнаступним чином:

Var i; var sum;

Один раз використавши ключове слово var, можна оголосити кілька змінних:

Оголошення змінних можна поєднувати з їх ініціалізацією:

Var message = "привіт"; var i = 0, j = 0, k = 0;

Якщо початкове значення в інструкції var не задано, то змінна оголошується, але початкове значення залишається невизначеним (undefined), доки буде змінено програмою.

Якщо ви маєте досвід використання мов програмування зі статичними типами даних, таких як C# або Java, то можете помітити, що в оголошеннях змінних мовою JavaScriptвідсутнє оголошення типу. Змінні в JavaScript можуть зберігати значення будь-яких типів. Наприклад, у JavaScript допускається присвоїти деякій змінної число, а потім цієї ж змінної присвоїти рядок:

Var i = 10; i = "hello";

За допомогою інструкції var можна оголосити ту саму змінну кілька разів. Якщо повторне оголошення містить ініціалізатор, воно діє як звичайна інструкція присвоєння.

Якщо спробувати прочитати значення неоголошеної змінної, JavaScript згенерує помилку. У строгому режимі, передбаченому стандартом ECMAScript 5, помилка також порушується при спробі надати значення неоголошеної змінної. Однак історично і при виконанні не в строгому режимі, якщо присвоїти значення змінної, не оголошеної за допомогою інструкції var, JavaScript створить цю змінну як властивість глобального об'єкта, і вона діятиме практично так само, як коректно оголошена змінна. Це означає, що глобальні змінні не можна оголошувати. Однак це вважається поганою звичкою і може стати джерелом помилок, тому завжди намагайтеся оголошувати свої змінні за допомогою var.

Область видимості змінної

Область видимості (scope) змінної - це частина програми, на яку ця змінна визначена. Глобальна змінна має глобальну область видимості – вона визначена для всієї JavaScript-програми. У той самий час змінні, оголошені всередині функції, визначено лише у її тілі. Вони називаються локальними та мають локальну область видимості. Параметри функцій також вважаються локальними змінними, визначеними лише у тілі цієї функції.

Усередині тіла функції локальна змінна має перевагу перед глобальною змінною з тим самим ім'ям. Якщо оголосити локальну змінну або параметр функції з тим самим ім'ям, що у глобальній змінній, то фактично глобальна змінна буде прихована:

Var result = "global"; function getResult() ( var result = "local"; return result; ); console.log(getResult()); // Відобразить "local"

Оголошуючи змінні з глобальною областю видимості, інструкцію var можна опустити, але при оголошенні локальних змінних слід використовувати інструкцію var.

Змінні та константи у JavaScript. Оголошення змінних та присвоєння їм значень. Змінні глобальні та локальні. Використання констант.

Оголошення змінних у JavaScript

Імена змінних JavaScript можуть складатися з букв, цифр, знака $ і знака _, причому ім'я змінної не може починатися з цифри. Майте на увазі, що JavaScript чутливий до регістру літер, і змінні a1 та A1 – це різні змінні. Кирилицю використовувати не рекомендується, хоч це можливо.
Змінні JavaScript об'являються ключовим словом var:

Var Peremennaya_1 Var Peremennaya_2

Використовувати змінні JavaScript без оголошення не рекомендується. Це можливо, але може призвести до помилок.

Присвоєння значення змінним

Присвоєння значення оголошеним змінним JavaScript:

Peremennaya_1 = 25 Peremennaya_2 = "Текст, що надається, укладаємо в прямі лапки"

Можна надавати значення змінним відразу при оголошенні:

Var Peremennaya_1 = 25 var Peremennaya_2 = "Текст, що надається, укладаємо в прямі лапки"

Значення змінної JavaScript може змінюватися в процесі виконання програми. При записі в змінну тексту його необхідно укласти в прямі лапки.

Змінні локальні та глобальні

Якщо змінна оголошена всередині функції, вона є локальноюі буде доступна (мати видимість) тільки в межах цієї функції. При виході з функції локальні змінні JavaScript знищуються, тому в різних функціях можна використовувати змінні з одним і тим же ім'ям.

Якщо змінна оголошена поза функціями, то вона є глобальноюі буде доступна (мати видимість) у всіх функціях у межах сторінки. Глобальні змінні знищуються JavaScript під час закриття сторінки.

Константи у JavaScript

Константипризначені для спрощення роботи з кодом, коли доводиться використовувати значення або вирази, що повторюються. Достатньо одноразово задати константі значення і можна скільки завгодно його використовувати, вставляючи код своїх програм. JavaScript не має ключового слова для оголошення констант, замість констант використовуються звичайні змінні. Щоб константи відрізнялися від змінних їх прийнято позначати великими літерами, при необхідності використовуючи знак підкреслення:

Var DRUG_CHELOVEKA = "Собака"

Наведений приклад константи не зовсім повноцінний, тому що слово «Собака» і так нескладно запам'ятати та вставляти куди треба. Використовувати константи в JavaScript можна для запису і вставки складніших значень, наприклад, кодів, наборів символів, що важко запам'ятовуються, довгого тексту, веб-адрес, адрес електронної пошти, телефонних номерів, різних коефіцієнтів

У JavaScript константи можна перезаписувати як змінні, але якщо це робити, тоді втрачається сенс констант.

У цьому уроці з чотирьох частин порушуються питання написання якісного коду JavaScript, який легко підтримуватиме і розвиватиметься, навіть якщо до проекту доводиться повертатися через тривалий час.

Пишіть код із розрахунком, що його треба буде підтримувати

Помилки програмного забезпеченнямають власну вартість. Їхня вартість виражається в часі, який необхідно витратити на їх виправлення. Особливо дорого обходяться помилки у публічно запущених проектах. Дуже добре, якщо ви можете виправити помилки відразу, коли структура коду ще свіжа у пам'яті, і можна досить швидко знайти проблемне місце. Але якщо ви переключилися на інші завдання і вже призабули особливості певного коду, то повернення до проекту вимагатиме:

  • Час на вивчення та розуміння проблеми.
  • Час розуміння коду, що є джерелом проблеми.

Ще одна проблема, що стосується великих проектів або компаній, полягає в тому, що людина, яка виправляє помилки, не є тією людиною, яка їх створює (а часто і не є тим, хто їх знаходить у проекті). Тому зменшення часу для розуміння коду стає критичним питанням незалежно від того, чи ви писали код самі деякий час тому, чи він написаний іншим розробником вашої команди. Відповідь на питання істотно впливатиме і на фінансовий результат проекту і на рівень задоволення розробників, тому що іноді краще зробити все по-новому, ніж витрачати години та дні на підтримку старого незрозумілого коду.

Іншим фактом, пов'язаним з розробкою програмного забезпечення, є те, що зазвичай більше часу займає читаннякоду, а чи не його створення. При початковій постановці завдання розробник фокусується і занурюється в питання, а потім сідає і може за один вечір створити суттєвий за обсягом код. Потім код, ймовірно, працює, але, за природною натурою програмних продуктів, виникають ситуації, що вимагають повторного перегляду коду. Наприклад:

  • Виявляються помилки.
  • Нові функції додаються до проекту.
  • Програму треба запустити в новому оточенні (наприклад, з'явився новий браузер).
  • Змінюється призначення коду.
  • Код потрібно повністю переписати або портувати на іншу архітектуру чи мову програмування.

В результаті, на написання коду буде витрачено кілька людино-годин, а на читання - кілька людино-днів. Тому створення коду, що легко підтримується, є критичним питанням для успіху програми.

Код, що легко підтримується, має такі ознаки:

  • Він легко читається.
  • Він добре структурований і частини узгоджені між собою.
  • Він передбачуваний.
  • Виглядає так, ніби написано однією людиною.
  • Документовано.

Мінімізація використання глобальних змінних

JavaScript використовує функції для керування контекстом. Змінні, що оголошуються всередині функцій, є локальними для них і недоступні поза функціями. Глобальні змінні оголошуються поза функціями або просто використовуються без оголошення.

Кожне оточення JavaScript має глобальний об'єкт, який використовується поза функціями. Кожна глобальна змінна, що ви створюєте, стає властивістю глобального об'єкта. У браузерах для зручності існує додаткова властивість глобального об'єкта, яка називається window і яка (зазвичай) вказує на сам глобальний об'єкт. Наступний код показує приклад створення та доступу до глобальних змінних в оточенні браузера:

Var myglobal = "hello"; console.log(myglobal); // "hello" console.log(window.myglobal); // "hello" console.log(window["myglobal"]); // "hello" console.log(this.myglobal); // "hello"

Проблеми з глобальними змінними

Проблеми з глобальними змінними полягають у тому, що вони будуть доступні у всьому коді JavaScript вашої програми або сторінки. Вони знаходяться у глобальному просторі імен, і завжди є шанс для колізій іменування, коли дві різні частини програми визначають глобальні змінні з однаковим ім'ям, але для різних цілей.

Також, як правило, веб-сторінка включає код, написаний іншими розробниками. Наприклад:

  • Інші бібліотеки JavaScript.
  • Скрипти партнерів із реклами.
  • Код для відстеження користувачів та аналітики.
  • Різні віджети, кнопки та плагіни.

Допустимо, в одному із сторонніх скриптів визначається глобальна змінна, яка називається, наприклад, result . Потім ви в одній зі своїх функцій визначаєте іншу глобальну змінну і називаєте її результатом. В результаті, останнє оголошення змінної результат перекриє перше, і сторонній скрипт може перестати працювати.

Отже, для успішного поєднання різного коду на одній сторінці важливо використовувати якнайменше глобальних змінних. У цьому питанні істотну роль грає використання директиви var при оголошенні змінних.

На жаль, дуже просто мимоволі створити глобальну змінну JavaScript через дві його особливості. По-перше, ви можете використовувати змінну без оголошення. По-друге, JavaScript має визначення очевидного глобального, яке означає, що будь-яка змінна без оголошення стає властивістю глобального об'єкта (і буде доступна як правильно оголошена глобальна змінна). Наприклад:

Function sum(x, y) ( // погано: мається на увазі глобальне result = x + y; return result; )

У цьому коді змінна результат використовується без оголошення. Код відмінно працює, але після виклику функції ви отримаєте ще одну змінну result у глобальному просторі імен, що може призвести до проблем.

Правило мінімізації полягає у визначенні змінних за допомогою директиви var. Нижче наводиться покращена версія функції sum() :

Function sum(x, y) ( var result = x + y; return result; )

Ще один поганий варіант для створення передбачуваних глобальних - це ланцюжкове надання значення в рамках оголошення var. У наступному прикладі змінна a буде локальною, а змінна b стане глобальною, що, напевно, не входить до списку цілей творця коду:

// погано, не треба використовувати function foo() ( var a = b = 0; // ... )

Якщо ви здивовані тим, що відбувається, то справа тут у обчисленнях справа-наліво. Спочатку виконується вираз b = 0 і тому змінна b не буде оголошена. Значення, що повертається, буде 0, і воно присвоюється нової локальної змінної a , яка оголошена директивою var. Таке визначення змінних еквівалентно наступному запису:

Var a = (b = 0);

Якщо ви вже оголосили змінні, то ланцюжкове уявлення добре працюватиме і не створить небажаних глобальних змінних:

Function foo() ( var a, b; a = b = 0; // обидві змінні є локальними )

Ще однією причиною уникати використання глобальних змінних є портованість коду. Якщо ви плануєте запускати код в іншому оточенні, то глобальні змінні можуть переписати об'єкти, які відсутні в оригінальному оточенні (тому може здатися, що ім'я, що використовується, безпечне).

Побічний ефект забутої декларації var

Є невелика різниця між явно визначеною і очевидною глобальними змінними. Вона полягає у можливості видалення змінної за допомогою оператора delete:

  • Глобальна змінна, оголошена декларацією var (створена у програмі поза функціями) не може бути видалена.
  • Зрозуміла глобальна змінна, створена без оголошення (незалежно від місця створення) може бути видалена.

Технічно, що розуміється глобальна змінна є властивістю глобального об'єкта, а не змінною. Властивості можуть бути видалені за допомогою оператора delete, а змінні – ні:

// Визначаємо три глобальних змінних var global_var = 1; global_novar = 2; // погано (function () (global_fromfunc = 3; // погано) ()); //Пробуємо видалити delete global_var; // false delete global_novar; // true delete global_fromfunc; // true // Перевірка видалення typeof global_var; // "number" typeof global_novar; // "undefined" typeof global_fromfunc; // "undefined"

Доступ до глобального об'єкту

У браузерах глобальний об'єкт доступний у будь-якій точці коду через властивість window (доки ви не зробите щось спеціальне або несподіване, наприклад, оголосіть локальну змінну з ім'ям window). Але в інших середовищах оточення ця зручна властивість може бути доступна в інший спосіб (або навіть взагалі недоступна програмісту). Якщо вам потрібний доступ до глобального об'єкта без використання ідентифікатора window, то ви можете використовувати наступний спосіб на будь-якому рівні вкладеного простору імен функції:

Var global = (function () ( return this; )());

Таким чином, завжди можна отримати доступ до глобального об'єкта, тому що всередині функції, яка викликана як функція (а не як конструктор з декларацією new), це завжди вказує на глобальний об'єкт.

Шаблон одного оголошення var

Використання одного оголошення var вгорі вашої функції є дуже корисною практикою. Такий метод має такі переваги:

  • Забезпечується єдине місце для оголошення всіх локальних змінних функцій.
  • Запобігають логічні помилки, коли змінна використовується раніше, ніж вона оголошується.
  • Допомагає пам'ятати про оголошення локальних змінних і, отже, скорочує кількість глобальних змінних.

Шаблон з одним оголошенням var виглядає так:

Function func() ( var a = 1, b = 2, sum = a + b, myobject = (), i, j; // Код функції ... )

Ви використовуєте одну декларацію var для оголошення кількох змінних, розділених комою. Відмінним доповненням буде ініціалізація змінних вихідними даними за їхнього оголошення. Так запобігають логічні помилки (усі неініціалізовані змінні за замовчуванням набувають значення undefined) і покращується читабельність коду. Коли ви пізніше переглядатимете код, як ви зможете визначити призначення змінної за її початкового значення(Наприклад, відразу буде видно, що це об'єкт або ціле число).

Також можна виконати операцію при оголошенні змінної, наприклад sum = a + b з попереднього коду прикладу. Іншим робочим прикладом є оперування з DOM. Ви можете призначати посилання на елементи DOM локальним змінним під час оголошення:

Function updateElement() ( var el = document.getElementById("result"), style = el.style; // виконуємо операції з el і style... )

Підйом: проблема з розкиданими деклараціями var

JavaScript дозволяє використовувати кілька декларацій var в будь-якому місці функції, і вони діють однаково, незалежно від місця розміщення. Ця особливістьвідома як "підйом". Таке функціонування може призвести до логічних помилок, коли ви використовуєте змінну, а потім оголошує її для подальшого коду функції. Для JavaScript, оскільки змінна знаходиться в одному просторі імен (в одній функції), передбачається її оголошення навіть якщо вони використовуються до директиви var . Наприклад

// погано myname = "global"; // глобальна змінна function func() ( alert(myname); // "undefined" var myname = "local"; alert(myname); // "local" ) func();

У даному прикладіочікується, перший виклик функції alert() видасть повідомлення “global”, а другий - “local.” Розумне очікування, оскільки при першому виклику локальна змінна myname не оголошена, і функція має використовувати глобальну змінну myname . Але насправді все працює інакше. Перший виклик функції alert() видасть “undefined” тому, що myname розглядається як оголошена локальна змінна функції (хоча оголошення буде пізніше). Всі оголошення змінних піднімаються догори функції. Отже, щоб уникнути такого типу помилок, потрібно оголошувати всі перемінні вгорі функції.

Попередній приклад діятиме так, ніби він був реалізований таким чином:

Myname = "global"; // глобальна змінна function func() ( var myname; // те саме, що і -> var myname = undefined; alert(myname); // "undefined" myname = "local"; alert(myname); // " local" ) func();

Варто згадати, що насправді реалізація коду складніша. Існують дві стадії обробки коду. На першій стадії створюються змінні, оголошення функцій та формальні параметри, а також визначається контекст. На другій стадії виконується код, обчислення функцій та створюються некваліфіковані ідентифікатори (неоголошені змінні). Але для практичного застосування можна використовувати концепцію підйому, яка добре описує поведінку коду.