Программирование 101: Что такое глобальная переменная (и безопасна ли она?)

Программирование 101: Что такое глобальная переменная (и безопасна ли она?)

Глобальные переменные вызывают разногласия: бесценный способ сокращения или опасный пример неряшливого кода? Давайте поговорим о том, что они делают, для чего они хороши и почему следует быть особенно осторожными при их использовании.

Что такое глобальная переменная?

Компьютерная программа — это, по сути, список инструкций, которые компьютер должен выполнить при запуске. Однако большинство программ достаточно сложны, чтобы перерасти простой список из одной строки. Такие структуры, как блоки, функции и определения классов, могут помочь вам организовать код, сделав его более управляемым.

Функции — это самый базовый инструмент, который вы можете использовать для группировки кода, изолируя его поведение от остальной части вашей программы. Вы можете вызывать функцию из других частей вашего кода и повторно использовать ту же логику без необходимости дублировать ее снова и снова.

Вот пример функции JavaScript, которая использует два типа переменных: аргумент функции и локальную переменную:

функция факториал(x) {
    пусть я;

    для (i = x — 1; i > 0; i—)
        х *= я;

    вернуть x;
}

факториал(4); // 24

Аргумент функции x автоматически заполняется значением, переданным функции при ее вызове. В приведенном выше примере он принимает значение 4.

Переменная i объявляется с помощью ключевого слова let. Это гарантирует, что она является локальной переменной. Изначально ее значение не определено, до того как цикл for присваивает и изменяет ее значение.

Каждая переменная ограничена функцией факториала; никакой другой код не может считывать или записывать значения x или i. Вы можете запустить этот JavaScript в консоли браузера и убедиться, что переменные x и i не видны за пределами функции:

Программирование 101: Что такое глобальная переменная (и безопасна ли она?)

JavaScript также поддерживает глобальные переменные, которые имеют область действия во всей программе. Вот альтернативная версия функции факториала, которая требует от вас установки глобальной переменной перед вызовом, а не передачи аргумента:

функция факториал() {
    пусть я;

    для (i = x — 1; i > 0; i—)
        х *= я;

    вернуть x;
}

var x = 4;
факториал(); // 24

Это очень неортодоксальный тип функции, непрактичный и используемый здесь только для демонстрации потенциального использования глобальных переменных. Он работает, но он неуклюж и более неудобен в использовании. Фактически, этот подход напоминает старый ассемблерный код, в котором вообще не было концепции функций.

Большинство языков программирования поддерживают глобальные переменные, но они, как правило, делают это по-разному. Например, PHP использует ключевое слово global для доступа к переменной, объявленной вне любой функции:

$ a = 0;
$б = 0;

функция inc() {
    глобальный $a;
    $ a = 2;
    $б = 2;
}

inc();
echo «a — это $a, а b — это $bn»;

В этом коде функция inc использует ключевое слово global для доступа к переменной $a, объявленной на верхнем уровне. Когда она устанавливает $a, она изменяет эту переменную верхнего уровня, поэтому вывод подтверждает, что она имеет значение 2. Однако $b не объявлена ​​глобальной внутри inc, поэтому функция изменяет только локальную переменную, которая, как оказалось, имеет то же имя. Исходная переменная верхнего уровня сохраняет свое значение 0.

Как можно неправильно использовать глобальные переменные?

Основная проблема с глобальными переменными заключается в том, что они нарушают инкапсуляцию, создавая обширный потенциал для ошибок. Рассмотрим этот пример:

var days = [ «Воскресенье», «Понедельник», «Вторник», «Среда»,
 «Четверг», «Пятница», «Суббота» ];

функция day_name(число) {
    дни возврата[число];
}

Функция day_name() обращается к глобальному массиву, чтобы вернуть название дня, заданное его номером. В небольшой программе это, вероятно, не проблема, но по мере роста длины и сложности программы ошибки могут процветать.

Для начала, поскольку переменная days является глобальной, любая другая часть кодовой базы может ее изменить. Следующий код может появиться где угодно и фундаментально изменить поведение day_name:

days[5] = «Я не знаю когда»;

В больших программах может быть сложно и долго идентифицировать части кода, которые используют или изменяют глобальную переменную.

Эта проблема становится еще серьезнее, если ваш код многопоточный. При запуске нескольких копий вашего кода гораздо сложнее гарантировать, что все они будут получать доступ к глобальным переменным и изменять их, не наступая друг другу на пятки.

Этот код также тесно связан, что затрудняет его тестирование. Введение зависимости между функцией и глобальной переменной означает, что они всегда должны сосуществовать, и тестирование функции в изоляции становится немного сложнее.

Программирование 101: Что такое глобальная переменная (и безопасна ли она?)

Чем больше у вас глобальных переменных, тем больше вероятность возникновения конфликтов имен. Для JavaScript это особая проблема из-за глобального объекта. В веб-браузере все глобальные переменные хранятся как свойства объекта Window. Это означает, что легко объявить глобальную переменную, которая переопределяет свойство Window, которое ваш код — или чей-то еще — предполагает присутствующим.

var alert = «нет, не надо»;

window.alert(«Нажмите ОК, чтобы продолжить»);

Вызов window.alert() завершится ошибкой, поскольку теперь это строка, а не функция. Хотя вы не напишете этот код намеренно, это очень легко сделать случайно. Чем больше глобальных переменных вы используете, тем больше вероятность, что вы наступите на мозоли другого кода. Вы можете попытаться избежать этого, используя более необычные имена для ваших глобальных переменных, но это всего лишь лейкопластырь; нет никаких гарантий, что ваш код будет безопасным.

Все эти проблемы могут быть более распространены, если вы используете внешние библиотеки, в зависимости от того, как ваш язык защищает вас. JavaScript предлагает здесь мало защиты, поэтому, если вы не будете осторожны, глобальные переменные могут сломать код используемой вами библиотеки — или наоборот.

И для чего нужны глобальные переменные?

Однако не все глобальные переменные плохи — на самом деле, иногда они необходимы, и избегать их любой ценой может быть дорого! Вот очень разумный пример:

var debug = true;

функция do_something() {
    пусть res = do_a_thing();
    
    если (отладка) {
        console.debug(«res был», res);
    }

    возврат рез;
}

Этот подход к отладке может быть полезен во время разработки и тестирования и отлично подходит для небольших программ. Однако он все еще уязвим для проблем, особенно из-за того, что любая часть кода может изменить значение debug; оно изменяемо. Чтобы избежать этого, лучше всего объявлять переменную как константу, если вы хотите предотвратить изменение ее значения:

const СЕКУНДЫ_В_МИНУТЕ = 60;

Важно отметить, что константа в JavaScript, строго говоря, не является глобальной. Во-первых, она не будет добавлена ​​как свойство объекта window. Но константа, объявленная вами на верхнем уровне скрипта, будет видна всему коду, который следует за ней.

Программирование 101: Что такое глобальная переменная (и безопасна ли она?)

Если вы используете глобальные переменные, вы также можете уменьшить вероятность проблем, используя один глобальный объект. Например, вместо:

переменная цвета = [0, 0, 255];
var debug = false;
вар дней = 7;

Вы можете сохранить те же значения в глобальной карте:

var all_my_globals = {
    цвет: [0, 0, 255],
    отладка: ложь,
    дней: 7,
    …
};

При таком подходе вы просто добавляете одно имя в глобальное пространство имен, поэтому меньше вероятность того, что оно будет конфликтовать с другими, и проще искать в коде использование этой переменной.

Наконец, документация — ваш друг. Если вам необходимо использовать глобальные переменные, убедитесь, что они объяснены в комментарии, особенно если вы рассматривали альтернативный подход, но в итоге отклонили его. Имена переменных также выступают в качестве документации, поэтому убедитесь, что вы используете понятные, краткие, конкретные имена, которые объясняют назначение каждой переменной.

Валентин Павлов/ автор статьи
Страсть Влентина к играм началась с Resident Evil, и с тех пор он не переставал играть в хоррор-игры. Пишет экспертные руководства для самых сложных игр и обзоры для самых громких релизов. Является магистром журналистики и имеет степень бакалавра лингвистики. Любимые игры: GTA 5, Silent Hill 2, Call of Duty: Modern Warfare 2, Heavy Rain, Metro 2033 и другие.
Понравилась статья? Поделиться с друзьями:
Добавить комментарий