Я слышал, что глобальные переменные неверны, какое альтернативное решение мне использовать?

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

Я думаю о функции, которая при подаче двух аргументов (function globalVariables(Variable,Value)) проверяет, существует ли переменная в локальном массиве, и если она устанавливает ее значение в Value, иначе добавляются Variable и Value. Если функция вызывается без аргументов (function globalVariables()), она возвращает массив. Возможно, если функция запускается только с одним аргументом (function globalVariables(Variable)), она возвращает значение Variable в массиве.

Что вы думаете? Хотелось бы услышать ваши альтернативные решения и аргументы в пользу использования глобальных переменных.

Как бы вы использовали globalVariables();

function append(){
    globalVariables("variable1","value1"); //globalVariables() would append variable1 to it's local array.
};

function retrieve(){
    var localVariable1 = globalVariables("variable1"); //globalVariables() would return "value1".
};

function retrieveAll(){
    var localVariable1 = globalVariables(); //globalVariables() would return the globalVariable()'s entire, local [persistently stored between calls] array.
};

function set(){
    globalVariables("variable1","value2"); //globalVariables() would set variable1 to "value2".
};

Это шаблон Singleton BTW?

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

Спасибо, я ценю вашу помощь!


person Jonathon Oates    schedule 10.04.2010    source источник
comment
Я не думаю, что вы понимаете, почему они плохие   -  person Yacoby    schedule 10.04.2010
comment
@Yacoby: Я думаю, что да [ответ Ли многое объясняет], но если вы считаете иначе, пожалуйста, уточните. Какое решение я должен использовать в этом сценарии?   -  person Jonathon Oates    schedule 10.04.2010
comment
Здесь я должен согласиться с @Yacoby. В своем примере вы как бы заново изобретаете глобальные переменные, поэтому возвращение к шагу одной из глобальных переменных - это плохо.   -  person Patrick    schedule 10.04.2010
comment
Хорошо, спасибо Якоби и Патрику, но как мне сделать переменную, постоянную между несколькими функциями, которые не вызывают друг друга, чтобы аргументы не могли быть отправлены?   -  person Jonathon Oates    schedule 10.04.2010
comment
Должен ли я хранить значение переменных в файле cookie, например, в качестве альтернативы?   -  person Jonathon Oates    schedule 10.04.2010
comment
@Jay В зависимости от того, какие значения вы хотите сохранить постоянными, вы можете использовать статические переменные (глобальные для каждого класса) или передавать их в качестве аргумента функциям, которым они нужны, как @Yacoby пишет в своем ответе ниже. Все зависит от модели, которую вы пытаетесь разработать.   -  person Patrick    schedule 10.04.2010
comment
Какую проблему вы пытаетесь решить с помощью своего решения и как оно ее решает?   -  person erikkallen    schedule 10.04.2010


Ответы (8)


Основная причина, по которой глобальные переменные не приветствуются в javascript, заключается в том, что в javascript весь код разделяет одно глобальное пространство имен, а также javascript подразумевает глобальные переменные, т.е. переменные, которые явно не объявлены в локальной области видимости, автоматически добавляются в глобальное пространство имен. Слишком большая зависимость от глобальных переменных может привести к конфликтам между различными скриптами на одной странице (прочтите статьи Дугласа Крокфорда ).

Один из способов уменьшить глобальные переменные - использовать шаблон модуля YUI. Основная идея состоит в том, чтобы заключить весь ваш код в функцию, которая возвращает объект, содержащий функции, к которым требуется доступ вне вашего модуля, и присвоить возвращаемое значение одной глобальной переменной.

var FOO = (function() {
    var my_var = 10; //shared variable available only inside your module

    function bar() { // this function not available outside your module
        alert(my_var); // this function can access my_var
    }

    return {
        a_func: function() {
            alert(my_var); // this function can access my_var
        },
        b_func: function() {
            alert(my_var); // this function can also access my_var
        }
    };

})();

теперь, чтобы использовать функции в вашем модуле в другом месте, используйте FOO.a_func(). Таким способом разрешить конфликты глобальных пространств имен вам нужно только изменить имя FOO.

person z33m    schedule 10.04.2010
comment
Это круто, потребуется полностью переписать мой код, но я закончил, круто, ответ принят. - person Jonathon Oates; 12.04.2010
comment
статья Крокфорда с описанием решения z33m yuiblog.com/blog/2006/06/ 01 / global-domination - person ychaouche; 11.12.2012
comment
хе-хе - последние две скобки - ошибка! без них вам нужно было бы обратиться к FOO().a_func(). Ах, теперь это обретает смысл! - person ErichBSchulz; 08.04.2013
comment
так что коллизии имен - единственная причина ?? или есть недостатки использования памяти также ?? - person bhavya_w; 12.09.2014
comment
Разве эта практика в основном не ориентирована на библиотеки или другой повторно используемый код? Если вы пишете собственный код для веб-приложения, которое, как правило, не находит применения где-либо еще - и при условии, что вы не называете их плохо или не используете плохие библиотеки, заполняющие глобальное пространство имен, - какая польза от этого в вашем веб-приложении? Просто как-то чище, за счет необходимости делать отступы для всего кода в каждом модуле? - person bryc; 08.07.2015
comment
Интересно, что здесь, в vanilla js, вызов функции находится за пределами круглых скобок, окружающих анонимную функцию. Но во всех шаблонах модуля node.js, которые я видел, вызов функции заключен в эти круглые скобки. Это имеет значение? И если да, то что это? - person krb686; 14.08.2016

Семантика мой мальчик. Семантика.

Начните с одного глобального: myApp = {}; В этом должно быть все. Единственным исключением будет ваша библиотека AJAX (есть несколько крайних исключений, например, работа с обратными вызовами JSONP).

В myApp должно быть очень мало свойств. Вы захотите хранить свойства своего приложения в контейнерах, таких как config или settings.

myApp = {
    config:{
        prop:1
    },
    settings:{
        prop:2
    },
    widgets:{
        List: function(props){},
        Item: function(props){}
    }
}

Тогда у вас может быть больше свойств в нижних модулях, компонентах, синглтонах и конструкторах классов (виджетах).

Эта настройка дает вам дополнительное преимущество, заключающееся в возможности доступа к любому свойству из любого другого места, поскольку вы можете получить его с помощью myApp global. Однако вы должны использовать "this", когда это возможно, потому что поиск выполняется быстрее. И просто установите свойство напрямую, не беспокойтесь о псевдогеттерах / сеттерах. Если вам действительно нужен геттер / сеттер, запрограммируйте его для этого конкретного использования.

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

И не умничай с частными переменными. Они тоже плохие: http://clubajax.org/javascript-private-variables-are-evil/

person mwilcox    schedule 10.04.2010
comment
отличный комментарий mwilcox. Я использовал этот пост, чтобы убедить в этом других присутствующих. - person Chris; 03.05.2013
comment
Вот как это делается. Единый глобал со всеми вашими варами, который обязательно должен быть доступен глобально. +1 - person welbornio; 11.06.2014
comment
Кто-нибудь знает об инструменте, который поможет преобразовать большое приложение, использующее глобальную область видимости, в такого рода? - person Don't Know; 20.08.2018

Глобальное состояние вызывает проблемы в нескольких областях. Один из них - повторное использование кода. Когда вы получаете доступ к некоторому глобальному состоянию, это означает, что компонент должен знать о своей среде (что-то вне себя). По возможности этого следует избегать, поскольку это делает компонент непредсказуемым.

Скажем, у меня есть объект, который обращается к вашей функции globalVariables, и я хочу использовать его на другой странице. Как мне узнать, как определить объект globalVariables или даже как его определить? Однако, если вы можете передать информацию в конструктор или в качестве аргумента функции, я могу легко определить, что требуется объекту.

Также, когда вы получаете доступ или изменяете глобальную область видимости, вы рискуете повлиять на другие объекты. Вот почему библиотеки, такие как jquery, используют только одно имя в глобальной области (наименее возможное). Это снижает вероятность конфликта с другими библиотеками. Другими словами, глобальная область действия находится вне вашего контроля, поэтому это опасно.

person Lee    schedule 10.04.2010

Как правило, использование глобальных переменных является плохой практикой, независимо от выбранного языка. Их даже (легко) не разрешается использовать в строгом режиме, что я очень рекомендую.

Рассмотрим этот фрагмент кода, который я нашел:

if (typeof session != 'undefined' && !data.cart.request_status)
  data.input_definitions.passengers =
    inflate_passenger(session, data.input_definitions.passengers);

Мне нужно было обернуться и спросить программиста felow, откуда взялась эта session переменная, так как поиск кода не обнаружился там, где она была установлена.

Оказалось, еще один пакет от компании устанавливает глобальную переменную. Кодируйте это как шутку: если вам нужно это объяснить, это, вероятно, не так уж и хорошо.

Временное решение с использованием ES6:

Находясь в Node, используйте import или require, чтобы привести желаемый материал в лексическую область видимости, не позволяйте людям касаться вашей глобальной среды без вашего ведома.

import {Sesssion} from 'api-core';
const Session = require('api-core').session;

Если вы используете внешний интерфейс, доставляющий код для браузера, вы не можете использовать import, если вы не транспилируете свой код ES6 с помощью Babel < / а>.

Пример транспиляции с использованием Gulp.js:

// $ npm install --save-dev gulp-babel babel-preset-es2015

// gulpfile.js
const gulp  = require('gulp');
const babel = require('gulp-babel');

gulp.task('transpile', () => {
  return gulp.src('src/app.js')
    .pipe(babel({presets: ['es2015']}))
    .pipe(gulp.dest('dist'));
});

// $ gulp transpile

Устаревшее решение:

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

// scripts/app.js
var MyApp = {
  globals: {
    foo: "bar",
    fizz: "buzz"
  }
};
person nicooga    schedule 19.08.2016

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

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

person Yacoby    schedule 10.04.2010
comment
... и если объекту нужен контекст, укажите его в качестве аргумента конструктора. - person Stephen C; 10.04.2010
comment
Спасибо, но в этом сценарии передача значений в качестве аргументов не сработает. Мне нужны различные переменные, которые остаются постоянными и доступны для нескольких функций. - person Jonathon Oates; 10.04.2010

Вы действительно не хотите этого делать.
Что касается того, почему вы видите, например, верхний пост здесь: Какой самый ЗЛОЙ код вы когда-либо видели в производственной корпоративной среде?

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

(function() {
  var notaglobal = 1;
  alert(notaglobal);
})();
//notaglobal is not defined in this scope

person Andras Vass    schedule 10.04.2010

Другой ответ наиболее объясняется анонимной функцией, поскольку упоминается в этой статье,

Анонимные функции сложно отлаживать, поддерживать, тестировать или повторно использовать.

Вот пример с нормальной функцией. Легче читать и понимать.

/* global variable example */

    var a= 3, b= 6;
    
    function fwithglobal(){
    console.log(a, b); // 3 6 expected
    }
    
    fwithglobal(); // first call
    
    function swithglobal(){
    var a=9;
    console.log(a, b); // not 3 6 but 9 6
    }
    
    swithglobal(); // second call
    

/* global variable alternative(function parameter) */

    function altern(){
    var a= 3, b= 6; // var keyword needed
      f_func(a,b);
      s_func(a,b);
    }
    
    function f_func(n, m){
    console.log(n, m); // 3 6 expected
    }
    
    function s_func(n, m){
    var a=9;
    console.log(n, m); // 3 6 expected
    }
    
    altern(); // only once

person Guspan Tanadi    schedule 17.09.2016

Глобальные переменные плохи ... если оставить их неуправляемыми!

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

Я не считаю, что нужно искать единственную альтернативу. Вместо этого я выступаю за один объект, отвечающий за управление этими глобальными объектами, и по мере развития базы кода / компонента реорганизуйте их.

Одна вещь, не упомянутая в текущих ответах, которая, на мой взгляд, важна, - это понимание контейнеров DI и IoC. Они решают многие проблемы, которые люди пытаются решить с помощью глобальных переменных, но покрывают связанные проблемы, которые не могут быть реализованы простыми глобальными переменными, например жизненные циклы объектов.

person SystematicFrank    schedule 21.04.2017