Я слышал, что глобальные переменные плохие, какое альтернативное решение я должен использовать? - PullRequest
67 голосов
/ 10 апреля 2010

Я везде читал, что глобальные переменные плохие и должны использоваться альтернативы. В частности, в 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 Pattern BTW?

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

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

Ответы [ 9 ]

127 голосов
/ 10 апреля 2010

Основная причина, по которой глобальные переменные не приветствуются в 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.

40 голосов
/ 10 апреля 2010

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

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

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

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

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

Эта настройка дает вам дополнительное преимущество возможности доступа к любому свойству из любого другого места, поскольку вы можете получить его с помощью myApp global. Тем не менее, вы должны использовать «это», когда это возможно, потому что поиск быстрее. И просто установите свойство напрямую, не мешайте псевдо-геттеру / сеттеру. Если вам действительно нужен метод получения / установки, закодируйте его для этого конкретного использования.

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

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

9 голосов
/ 10 апреля 2010

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

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

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

3 голосов
/ 19 августа 2016

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

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

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

Мне нужно было обернуться и спросить у программиста-флоу, откуда взялась эта переменная 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"
  }
};
3 голосов
/ 10 апреля 2010

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

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

(function () {
    var notaglobal = 1;
    alert(notaglobal);
})();
//notaglobal is not defined in this scope        
2 голосов
/ 10 апреля 2010

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

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

1 голос
/ 01 мая 2018

var ASHIVA_HandsOffNHS = (function() {
    
    // VARIABLES

    var my_var = 10;


    // PRIVATE FUNCTIONS
    
    function bar() {
        window.alert(my_var + 5);
    }


   // PUBLIC OBJECT

    myObject = {};
    
    myObject['a_func'] = function() {
            my_var += 10;
            window.alert(my_var);
        };
        
    myObject['b_func'] = function() {
            my_var = 0;
            window.alert(my_var);
        };

    return myObject;

})();

ASHIVA_HandsOffNHS.a_func();
ASHIVA_HandsOffNHS.b_func();
ASHIVA_HandsOffNHS.a_func();
1 голос
/ 17 сентября 2016

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

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

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

/* 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
0 голосов
/ 21 апреля 2017

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...