2010-04-10 19 views
58

He leído por todas partes que se deben usar global variables are bad y alternativas. En Javascript específicamente, ¿qué solución debería elegir?He oído que las variables globales son malas, ¿qué solución alternativa debería usar?

Estoy pensando en una función, que cuando se alimentan con dos argumentos (function globalVariables(Variable,Value)) mira si existe variable en un array local y si no establece su valor a Value, de lo contrario, Variable y Value se adjuntan. Si se llama a la función sin argumentos (function globalVariables()) devuelve la matriz. Quizás si la función se dispara con un solo argumento (function globalVariables(Variable)), devuelve el valor de Variable en la matriz.

¿Qué opinas? Me gustaría escuchar sus soluciones alternativas y argumentos para usar variables globales.

cómo utilizaría 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". 
}; 

¿Es esta una Singleton Pattern cierto?

En este escenario específico, una función puede establecer una variable en un punto en el tiempo, y mucho más tarde otra función, tal vez cuando un usuario envía un formulario, necesitará obtener esa variable. Por lo tanto, la primera función no podía pasar la variable como un argumento a la función posterior ya que nunca se llamaría desde la primera.

Gracias, agradezco toda su ayuda!

+9

No creo que entiendas por qué son malos – Yacoby

+1

@Yacoby: Creo que sí [la respuesta de Lee explica mucho], pero si sientes lo contrario, por favor, detalla. ¿Qué solución debería usar en este escenario? –

+0

Tendría que estar de acuerdo con @Yacoby aquí. Está reinventando variables globales en su ejemplo, por lo que volver al paso uno de "las variables globales son malas". – Patrick

Respuesta

114

La razón principal por la cual las variables globales se desaniman en javascript es porque, en todo el código Javascript a compartir un único espacio de nombres global, las variables globales también javascript está implícita, es decir. las variables que no se declaran explícitamente en el ámbito local se agregan automáticamente al espacio de nombres global. Depender demasiado de variables globales puede provocar colisiones entre varios scripts en la misma página (lea douglas crockford's articles).

Una forma de reducir las variables globales es utilizar el YUI module pattern. La idea básica es ajustar todo el código en una función que devuelve un objeto que contiene funciones a las que se debe acceder fuera de su módulo y asignarle el valor de retorno a una única variable global.

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 
     } 
    }; 

})(); 

ahora para usar funciones en su módulo en otro lugar, use FOO.a_func(). De esta forma, para resolver los conflictos globales del espacio de nombres, solo necesita cambiar el nombre de FOO.

+0

Esto es genial, tomará una reescritura completa de mi código, pero estoy completamente terminado, impresionante, aceptada. –

+0

El artículo de crockford que describe la solución de z33m http://www.yuiblog.com/blog/2006/06/01/global-domination/ – ychaouche

+4

heh heh - ¡esos dos últimos corchetes son una sorpresa! sin ellos, necesitarías referirte a 'FOO(). a_func()'. ¡Ah, empieza a tener sentido ahora! – ErichBSchulz

2

El problema con su solución es que solo hace que codifique más difícil de entender a la vez que mantiene todas las desventajas de las variables globales. La página a la que vinculó cubre los problemas. El único problema que su solución propuesta realmente resuelve es la contaminación del espacio de nombres, pero a costa de no poder ver qué variables globales se declaran tan fácilmente como la declaración es una llamada a la función).

La solución es escribir código sin variables globales. Si una función necesita un valor, páselo como argumento.

+2

... y si un objeto necesita contexto, proporciónalo como un argumento de constructor. –

+0

Gracias, pero en este escenario pasar valores ya que los argumentos no funcionarían. Necesito varias variables que permanecen persistentes y son accesibles para varias funciones. –

7

Estado global provoca problemas en varias áreas. Uno es la reutilización del código. Cuando accede a un estado global, significa que el componente debe conocer su entorno (algo externo a él). Debe evitar esto tanto como sea posible, ya que hace que el componente sea impredecible.

Digamos que tengo un objeto que accede a su función globalVariables y quiero usarlo en otra página. ¿Cómo sé definir el objeto globalVariables o incluso cómo definirlo? Sin embargo, si puede pasar la información a un constructor o como argumento a una función, entonces puedo determinar fácilmente qué se requiere para el objeto.

Además, cuando accede o modifica el alcance global, corre el riesgo de afectar a otros objetos. Esta es la razón por la cual las bibliotecas como jquery usan solo un nombre en el alcance global (el menos posible). Disminuye la posibilidad de conflicto con otras bibliotecas. En otras palabras, el alcance global está fuera de tu control, por lo que es peligroso.

34

Semántica my boy. Semántica.

Comience con un global: myApp = {}; Todo debería estar en eso. La única excepción sería su biblioteca AJAX (hay algunas excepciones extremas, como trabajar con devoluciones de llamada JSONP).

Deben existir muy pocas propiedades en myApp. Deberá mantener las propiedades de la aplicación en contenedores como configuración o configuración.

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

entonces puede que tenga más propiedades en módulos inferiores, componentes únicos y constructores de clase (widgets).

Esta configuración le brinda la ventaja adicional de poder acceder a cualquier propiedad desde cualquier otra ubicación ya que puede obtenerla con myApp global. Sin embargo, debe usar "esto" siempre que sea posible porque la búsqueda es más rápida. Y simplemente establece la propiedad directamente, no te molestes con las cosas pseudo getter/setter. Si realmente necesita un getter/setter, codifíquelo para ese uso específico.

El motivo por el que su ejemplo no funciona es porque es demasiado genérico y parece que busca una excusa para trabajar en el espacio global.

Y no te vuelvas inteligente con las variables privadas. Son demasiado mal: http://clubajax.org/javascript-private-variables-are-evil/

+0

Comentario muy bueno y valioso. Gracias. – ychaouche

+2

buen comentario mwilcox. Utilicé este post para convencer a los demás aquí en el trabajo de esto. – Chris

+0

Así es como se hace. Un único global con todos sus vars que absolutamente debe ser accesible globalmente. +1 – welbornio

2

El uso de variables globales es, en general, una mala práctica, independientemente del idioma de su elección. Ni siquiera se les permite usar (fácilmente) cuando están en strict mode, lo cual recomiendo encarecidamente.

consideran este trozo de código que encontró:

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

que tenía que dar la vuelta y pedir un programador felow donde hizo esta variable session viene, ya que ningún código de búsqueda apareció donde se estableció.

Resulté que otro paquete de la empresa establece la variable global. Código es como una broma: si necesita explicarlo, probablemente no sea tan bueno.

Solución usando ES6:

Si en el nodo, utilice import o require para llevar el material deseado en ámbito léxico, no deje que la gente se toca su entorno global sin que usted lo sepa.

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

Si usted está en la interfaz de la entrega de código para el navegador no se puede utilizar a menos que import transpile su código ES6 usando Babel.

Ejemplo transpiling utilizando 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 

Legado de solución:

Al usar funciones de ES6 no es una opción la única solución para el uso de un montón de variables globales, está utilizando una sola , y tienen la esperanza:

// scripts/app.js 
var MyApp = { 
    globals: { 
    foo: "bar", 
    fizz: "buzz" 
    } 
}; 
1

Otra respuesta más explicar con función anónima como this mención de artículo,

Las funciones anónimas son difíciles de depurar, mantener, probar o reutilizar.

Aquí hay un ejemplo con la función normal. Es más fácil de leer y entender

/* 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

Las variables globales son malos ... no ser gestionada!

Los riesgos potenciales de las variables globales son tan altos como las ganancias de placer y productividad de tener objetos usados ​​frecuentemente listos para usar.

No creo que se deba buscar una sola alternativa. En su lugar, defiendo un objeto a cargo de gestionar esos globales y como el código base/componente madura, refactorizarlos

Una cosa no mencionada en las respuestas actuales que creo que es crítica es la comprensión de los contenedores DI y IoC. Estos abordan muchos de los problemas que las personas intentan resolver con variables globales, pero que cubren preocupaciones relacionadas que los globales comunes no pueden, como los ciclos de vida de los objetos.

Cuestiones relacionadas