Я слышал, что глобальные переменные плохие, какое альтернативное решение я должен использовать?
Я читал повсюду, что глобальные переменные плохие и альтернативы должны быть использованы. В частности, в 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?
В этом конкретном сценарии функция может устанавливать переменную в один момент времени, и гораздо позже другой функции, возможно, когда пользователь отправляет форму, потребуется получить эту переменную. Поэтому первая функция не может передать переменную в качестве аргумента более поздней функции, поскольку она никогда не будет вызываться из первой.
Спасибо, я ценю вашу помощь!
9 ответов
Основная причина, по которой глобальные переменные не поощряются в 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
,
Семантика моего мальчика. Семантика.
Начните с одного глобального: myApp = {}; Все должно быть в этом. Единственным исключением будет ваша библиотека AJAX (есть некоторые крайние исключения, такие как работа с обратными вызовами JSONP).
В myApp должно быть очень мало свойств. Вы захотите хранить свойства вашего приложения в контейнерах, таких как config или настройки.
myApp = {
config:{
prop:1
},
settings:{
prop:2
},
widgets:{
List: function(props){},
Item: function(props){}
}
}
Тогда у вас может быть больше свойств в нижних модулях, компонентах, синглетонах и конструкторах классов (виджетах).
Эта настройка дает вам дополнительное преимущество возможности доступа к любому свойству из любого другого места, поскольку вы можете получить его с помощью myApp global. Тем не менее, вы должны использовать "это", когда это возможно, потому что поиск быстрее. И просто установите свойство напрямую, не беспокойтесь о псевдо-методах получения / установки. Если вам действительно нужен метод получения / установки, закодируйте его для этого конкретного использования.
Причина, по которой ваш пример не работает, в том, что он слишком общий, и вы, похоже, ищете повод для работы в глобальном пространстве.
И не умничайте с частными переменными. Они тоже плохие: http://clubajax.org/javascript-private-variables-are-evil/
Глобальное состояние вызывает проблемы в нескольких областях. Одним из них является повторное использование кода. Когда вы получаете доступ к какому-то глобальному состоянию, это означает, что компонент должен знать о своей среде (что-то вне себя). Вы должны избегать этого в максимально возможной степени, потому что это делает компонент непредсказуемым.
Скажем, у меня есть объект, который обращается к вашей функции globalVariables, и я хочу использовать его на другой странице. Как я знаю, чтобы определить объект globalVariables или даже как его определить? Однако, если вы можете передать информацию в конструктор или в качестве аргумента функции, тогда я легко могу определить, что требуется для объекта.
Также, когда вы получаете доступ или изменяете глобальную область действия, вы рискуете повлиять на другие объекты. Вот почему библиотеки, такие как jquery, используют только одно имя в глобальной области видимости (наименьшее возможное). Это уменьшает вероятность конфликта с другими библиотеками. Другими словами, глобальный охват находится вне вашего контроля, поэтому он опасен.
Использование глобальных переменных, вообще говоря, является плохой практикой, независимо от языка выбора. Их даже (легко) не разрешено использовать в строгом режиме, что я настоятельно рекомендую.
Рассмотрим этот фрагмент кода, который я нашел:
if (typeof session != 'undefined' && !data.cart.request_status)
data.input_definitions.passengers =
inflate_passenger(session, data.input_definitions.passengers);
Мне нужно было обернуться и спросить у флоу-программиста, где это было session
переменная пришла, так как поиск кода не показал, где был установлен.
У меня получился еще один пакет от компании, задающей глобальную переменную. Код это как шутка: если вам нужно это объяснить, это, вероятно, не так хорошо.
Обходной путь с использованием ES6:
Если на узле, используйте 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"
}
};
Вы действительно не хотите этого делать.
Почему, см., Например, верхний пост здесь: Какой самый злой код вы когда-либо видели в рабочей среде предприятия?
Как примечание, всегда можно выполнить "глобальный" код, не засоряя место глобалами:
(function () {
var notaglobal = 1;
alert(notaglobal);
})();
//notaglobal is not defined in this scope
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();
Проблема с вашим решением состоит в том, что он просто усложняет понимание кода, сохраняя при этом все недостатки глобальных переменных. Страница, на которую вы ссылаетесь, охватывает проблемы. Единственная проблема, которую предложенное вами решение действительно решает, - это загрязнение пространства имен, но за счет невозможности увидеть, какие глобальные переменные объявляются так же легко, как объявление является вызовом функции).
Решением является написание кода без глобальных переменных. Если функция нуждается в значении, передайте его в качестве аргумента.
Другой ответ, который большинство объясняют анонимной функцией, как упомянуто в этой статье
Анонимные функции сложно отлаживать, поддерживать, тестировать или использовать повторно.
Вот пример с нормальной функцией. Это легче читать и понимать.
/* 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
Глобальные переменные плохие... если их оставить неуправляемыми!
Потенциальные риски глобальных переменных так же высоки, как удовольствие и производительность от того, что часто используемые объекты готовы к использованию.
Я не верю, что нужно искать единственную альтернативу. Вместо этого я выступаю за один объект, отвечающий за управление этими глобальными переменными, и по мере развития базы / компонента кода их рефакторинг
Одна вещь, не упомянутая в текущих ответах, которую я считаю критической, - это понимание контейнеров DI и IoC. Они решают многие проблемы, которые люди пытаются решить с помощью глобальных переменных, но охватывают связанные с этим проблемы, которые обычные глобалы не могут, например, жизненные циклы объектов.