una - Variables estáticas en JavaScript
print data javascript (30)
¿Cómo puedo crear variables estáticas en Javascript?
Acerca de la class
introducida por ECMAScript 2015. Las otras respuestas no son totalmente claras.
Aquí hay un ejemplo que muestra cómo crear una staticVar
static staticVar
con el ClassName
. var
synthax:
class MyClass {
constructor(val) {
this.instanceVar = val;
MyClass.staticVar = 10;
}
}
var class1 = new MyClass(1);
console.log(class1.instanceVar); // 1
console.log(class1.constructor.staticVar); // 10
// New instance of MyClass with another value
var class2 = new MyClass(3);
console.log(class1.instanceVar); // 1
console.log(class2.instanceVar); // 3
Para acceder a la variable estática usamos la propiedad .constructor
que devuelve una referencia a la función constructora de objetos que creó la clase. Podemos llamarlo en las dos instancias creadas:
MyClass.staticVar = 11;
console.log(class1.constructor.staticVar); // 11
console.log(class2.constructor.staticVar); // 11 <-- yes it''s static! :)
MyClass.staticVar = 12;
console.log(class1.constructor.staticVar); // 12
console.log(class2.constructor.staticVar); // 12
Además del resto, actualmente hay un borrador (propuesta de la etapa 2 ) sobre las propuestas de ECMA que introduce campos públicos static
en las clases. ( campos privados fueron considerados )
Usando el ejemplo de la propuesta, la sintaxis static
propuesta se verá así:
class CustomDate {
// ...
static epoch = new CustomDate(0);
}
y ser equivalente a lo siguiente que otros han resaltado:
class CustomDate {
// ...
}
CustomDate.epoch = new CustomDate(0);
A continuación, puede acceder a través de CustomDate.epoch
.
Puede realizar un seguimiento de la nueva propuesta en proposal-static-class-features
.
Actualmente, Babel admite esta función con el complemento de propiedades de la clase de transformación que puede utilizar. Además, aunque todavía está en progreso, V8
está implementando .
El siguiente ejemplo y explicación son del libro Professional JavaScript for Web Developers 2nd Edition de Nicholas Zakas. Esta es la respuesta que estaba buscando, así que pensé que sería útil agregarla aquí.
(function () {
var name = '''';
Person = function (value) {
name = value;
};
Person.prototype.getName = function () {
return name;
};
Person.prototype.setName = function (value) {
name = value;
};
}());
var person1 = new Person(''Nate'');
console.log(person1.getName()); // Nate
person1.setName(''James'');
console.log(person1.getName()); // James
person1.name = ''Mark'';
console.log(person1.name); // Mark
console.log(person1.getName()); // James
var person2 = new Person(''Danielle'');
console.log(person1.getName()); // Danielle
console.log(person2.getName()); // Danielle
El constructor de Person
en este ejemplo tiene acceso al nombre de la variable privada, al igual que los métodos getName()
y setName()
. Al usar este patrón, la variable de nombre se vuelve estática y se usará entre todas las instancias. Esto significa que llamar a setName()
en una instancia afecta a todas las demás instancias. Al llamar a setName()
o al crear una nueva instancia de Person
, se establece la variable de nombre en un nuevo valor. Esto hace que todas las instancias devuelvan el mismo valor.
En JavaScript las variables son estáticas por defecto. Ejemplo :
var x = 0;
function draw() {
alert(x); //
x+=1;
}
setInterval(draw, 1000);
El valor de x se incrementa en 1 cada 1000 milisegundos
Se imprimirá 1,2,3 así sucesivamente.
En JavaScript, no hay un término o palabra clave estática, pero podemos colocar dichos datos directamente en el objeto de función (como en cualquier otro objeto).
function f() {
f.count = ++f.count || 1 // f.count is undefined at first
alert("Call No " + f.count)
}
f(); // Call No 1
f(); // Call No 2
Hay otras respuestas similares, pero ninguna de ellas me atrajo. Esto es lo que terminé con:
var nextCounter = (function () {
var counter = 0;
return function() {
var temp = counter;
counter += 1;
return temp;
};
})();
Hay otro enfoque, que resolvió mis requisitos después de navegar este hilo. Depende de exactamente lo que quieres lograr con una "variable estática".
La propiedad global sessionStorage o localStorage permite que los datos se almacenen durante la vida de la sesión, o por un período indefinido más largo hasta que se borren explícitamente, respectivamente. Esto permite compartir datos entre todas las ventanas, marcos, paneles de pestañas, ventanas emergentes, etc. de su página / aplicación y es mucho más poderoso que una simple "variable estática / global" en un segmento de código.
Evita toda molestia con el alcance, el tiempo de vida, la semántica, la dinámica, etc. de las variables globales de nivel superior, es decir, Window.myglobal. No sé qué tan eficiente es, pero eso no es importante para cantidades de datos modestas, a las que se accede a tasas moderadas.
Se accede fácilmente como "sessionStorage.mydata = cualquier cosa" y se recupera de manera similar. Consulte "JavaScript: La Guía Definitiva, Sexta Edición", David Flanagan, ISBN: 978-0-596-80552-4, Capítulo 20, sección 20.1. Esto se puede descargar fácilmente como PDF mediante una simple búsqueda o en su suscripción de O''Reilly Safaribooks (vale su peso en oro).
He visto un par de respuestas similares, pero me gustaría mencionar que esta publicación lo describe mejor, así que me gustaría compartirlo con ustedes.
Aquí hay algunos códigos tomados de él, que he modificado para obtener un ejemplo completo que, con suerte, beneficia a la comunidad porque se puede usar como plantilla de diseño para las clases.
También responde a tu pregunta:
function Podcast() {
// private variables
var _somePrivateVariable = 123;
// object properties (read/write)
this.title = ''Astronomy Cast'';
this.description = ''A fact-based journey through the galaxy.'';
this.link = ''http://www.astronomycast.com'';
// for read access to _somePrivateVariable via immutableProp
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return ''Title: '' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = ''mp3'';
// static function
Podcast.download = function(podcast) {
console.log(''Downloading '' + podcast + '' ...'');
};
Dado ese ejemplo, puede acceder a la función / propiedades estáticas de la siguiente manera:
// access static properties/functions
Podcast.FILE_EXTENSION; // ''mp3''
Podcast.download(''Astronomy cast''); // ''Downloading Astronomy cast ...''
Y las propiedades / funciones del objeto simplemente como:
// access object properties/functions
var podcast = new Podcast();
podcast.title = ''The Simpsons'';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
Tenga en cuenta que en podcast.immutableProp (), tenemos un closure : la referencia a _somePrivateVariable se mantiene dentro de la función.
Incluso puedes definir getters y setters . Eche un vistazo a este fragmento de código (donde d
es el prototipo del objeto para el que desea declarar una propiedad, y
es una variable privada no visible fuera del constructor):
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {return this.getFullYear() },
set: function(y) { this.setFullYear(y) }
});
Define la propiedad d.year
través de las funciones get
y set
: si no especifica set
, la propiedad es de solo lectura y no se puede modificar (tenga en cuenta que no obtendrá un error si intenta establecerla, pero no tiene efecto). Cada propiedad tiene los atributos de writable
, configurable
(permitir cambiar después de la declaración) y enumerable
(permitir usarlos como enumerador), que son por defecto false
. Puede establecerlos a través de defineProperty
en el tercer parámetro, por ejemplo, enumerable: true
.
Lo que también es válido es esta sintaxis:
// getters and setters - alternative syntax
var obj = { a: 7,
get b() {return this.a + 1;},
set c(x) {this.a = x / 2}
};
que define una propiedad de lectura / escritura a
, una propiedad de solo lectura b
y una propiedad de solo escritura c
, a través de la cual se puede acceder a la propiedad a.
Uso:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
Notas:
Para evitar un comportamiento inesperado en caso de que haya olvidado la new
palabra clave, le sugiero que agregue lo siguiente a la función Podcast
:
// instantiation helper
function Podcast() {
if(false === (this instanceof Podcast)) {
return new Podcast();
}
// [... same as above ...]
};
Ahora las dos siguientes instancias funcionarán como se espera:
var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast(); // you can omit the new keyword because of the helper
La declaración ''nueva'' crea un nuevo objeto y copia todas las propiedades y métodos, es decir,
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Tenga en cuenta también que , en algunas situaciones, puede ser útil usar la declaración de return
en el Podcast
función de constructor para devolver las funciones de protección de un objeto personalizado en las que la clase confía internamente, pero que deben ser expuestas. Esto se explica con más detalle en el capítulo 2 (Objetos) de la serie de artículos.
Puedes decir que a
y b
heredan de Podcast
. Ahora, ¿qué sucede si desea agregar un método a Podcast que se aplique a todos ellos después de que a
b
hayan sido instanciados? En este caso, utilice el .prototype
siguiente manera:
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
Ahora llama a
y b
otra vez:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
Puedes encontrar más detalles sobre prototipos here . Si quieres hacer más herencia, te sugiero que estudies this .
La serie de artículos que he mencionado anteriormente son muy recomendables de leer, incluyen también los siguientes temas:
- Funciones
- Objetos
- Prototipos
- Hacer cumplir lo nuevo en las funciones del constructor
- Levantamiento
- Inserción automática de punto y coma
- Propiedades y métodos estáticos
Tenga en cuenta que la "característica" automática de inserción de punto y coma de JavaScript (como se menciona en 6.) es a menudo responsable de causar problemas extraños en su código. Por lo tanto, prefiero verlo como un error que como una característica.
Si desea leer más, here hay un artículo de MSDN bastante interesante sobre estos temas, algunos de los que se describen allí brindan aún más detalles.
Lo que también es interesante de leer (que también cubre los temas mencionados anteriormente) son los artículos de la Guía de JavaScript de MDN :
Si desea saber cómo emular out
parámetros de out
c # (como en DateTime.TryParse(str, out result)
) en JavaScript, puede encontrar un código de muestra aquí.
Aquellos de ustedes que trabajan con IE (que no tiene una consola para JavaScript a menos que abra las herramientas del desarrollador utilizando F12 y abran la pestaña de la consola) pueden encontrar útil el siguiente fragmento de código. Te permite utilizar console.log(msg);
como se usa en los ejemplos anteriores. Simplemente insértelo antes de la función Podcast
.
Para su comodidad, aquí está el código anterior en un fragmento de código único completo:
let console = { log: function(msg) {
let canvas = document.getElementById("log"), br = canvas.innerHTML==="" ? "" : "<br/>";
canvas.innerHTML += (br + (msg || "").toString());
}};
console.log(''For details, see the explaining text'');
function Podcast() {
// with this, you can instantiate without new (see description in text)
if (false === (this instanceof Podcast)) {
return new Podcast();
}
// private variables
var _somePrivateVariable = 123;
// object properties
this.title = ''Astronomy Cast'';
this.description = ''A fact-based journey through the galaxy.'';
this.link = ''http://www.astronomycast.com'';
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return ''Title: '' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = ''mp3'';
// static function
Podcast.download = function(podcast) {
console.log(''Downloading '' + podcast + '' ...'');
};
// access static properties/functions
Podcast.FILE_EXTENSION; // ''mp3''
Podcast.download(''Astronomy cast''); // ''Downloading Astronomy cast ...''
// access object properties/functions
var podcast = new Podcast();
podcast.title = ''The Simpsons'';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {
return this.getFullYear()
},
set: function(y) {
this.setFullYear(y)
}
});
// getters and setters - alternative syntax
var obj = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2
}
};
// usage:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
<div id="log"></div>
Notas:
Algunos buenos consejos, sugerencias y recomendaciones sobre la programación de JavaScript en general se pueden encontrar aquí (mejores prácticas de JavaScript) y allí (''var'' versus ''let'') . También se recomienda este artículo sobre las tipografías implícitas (coerción) .
Una forma conveniente de usar clases y compilarlas en JavaScript es TypeScript. Aquí hay un patio de recreo donde puedes encontrar algunos ejemplos que muestran cómo funciona. Incluso si no está utilizando TypeScript en este momento, puede echar un vistazo porque puede comparar TypeScript con el resultado de JavaScript en una vista de lado a lado. La mayoría de los ejemplos son simples, pero también hay un ejemplo de Raytracer que puede probar al instante. Recomiendo especialmente buscar en los ejemplos de "Usar clases", "Usar herencia" y "Usar genéricos" seleccionándolos en el cuadro combinado: estas son buenas plantillas que puede usar instantáneamente en JavaScript.
Para lograr la encapsulación de variables locales, funciones, etc. en JavaScript, sugiero usar un patrón como el siguiente (JQuery usa la misma técnica):
<html>
<head></head>
<body><script>
''use strict'';
// module pattern (self invoked function)
const myModule = (function(context) {
// to allow replacement of the function, use ''var'' otherwise keep ''const''
// put variables and function with local module scope here:
var print = function(str) {
if (str !== undefined) context.document.write(str);
context.document.write("<br/><br/>");
return;
}
// ... more variables ...
// main method
var _main = function(title) {
if (title !== undefined) print(title);
print("<b>last modified: </b>" + context.document.lastModified + "<br/>");
// ... more code ...
}
// public methods
return {
Main: _main
// ... more public methods, properties ...
};
})(this);
// use module
myModule.Main("<b>Module demo</b>");
</script></body>
</html>
Por supuesto, puede, y debe, colocar el código de script en un archivo * .js separado; Esto solo está escrito en línea para mantener el ejemplo corto.
La función / classes permite solo un constructor único para su ámbito de objeto. Function Hoisting, declarations & expressions
Las funciones creadas con el constructor de funciones no crean cierres en sus contextos de creación; Siempre se crean en el ámbito global.
var functionClass = function ( ) { var currentClass = Shape; _inherits(currentClass, superClass); function functionClass() { superClass.call(this); // Linking with SuperClass Constructor. // Instance Variables list. this.id = id; return this; } }(SuperClass)
Closures : las copias de cierre funcionan con datos preservados.
- Las copias de cada cierre se crean para una función con sus propios valores o referencias libres. Siempre que utilice una función dentro de otra función, se utiliza un cierre.
Un cierre en JavaScript es como mantener una copia de todas las variables locales de su función principal mediante las funciones internas.
function closureFun( args ) { // Local variable that ends up within closure var num = args; num++; return function() { console.log(num); } } var closure1 = closureFun( 5 ); var closure2 = closureFun( 777 ); closure1(); // 5 closure2(); // 777 closure2(); // 778 closure1(); // 6
Clases de funciones ES5 : utiliza Object.defineProperty (O, P, atributos)
El método Object.defineProperty() define una nueva propiedad directamente en un objeto, o modifica una propiedad existente en un objeto, y devuelve el objeto.
Creé algunos métodos usando `` , para que cada vez puedan entender las clases de funciones fácilmente.
''use strict'';
var Shape = function ( superClass ) {
var currentClass = Shape;
_inherits(currentClass, superClass); // Prototype Chain - Extends
function Shape(id) { superClass.call(this); // Linking with SuperClass Constructor.
// Instance Variables list.
this.id = id; return this;
}
var staticVariablesJOSN = { "parent_S_V" : 777 };
staticVariable( currentClass, staticVariablesJOSN );
// Setters, Getters, instanceMethods. [{}, {}];
var instanceFunctions = [
{
key: ''uniqueID'',
get: function get() { return this.id; },
set: function set(changeVal) { this.id = changeVal; }
}
];
instanceMethods( currentClass, instanceFunctions );
return currentClass;
}(Object);
var Rectangle = function ( superClass ) {
var currentClass = Rectangle;
_inherits(currentClass, superClass); // Prototype Chain - Extends
function Rectangle(id, width, height) { superClass.call(this, id); // Linking with SuperClass Constructor.
this.width = width;
this.height = height; return this;
}
var staticVariablesJOSN = { "_staticVar" : 77777 };
staticVariable( currentClass, staticVariablesJOSN );
var staticFunctions = [
{
key: ''println'',
value: function println() { console.log(''Static Method''); }
}
];
staticMethods(currentClass, staticFunctions);
var instanceFunctions = [
{
key: ''setStaticVar'',
value: function setStaticVar(staticVal) {
currentClass.parent_S_V = staticVal;
console.log(''SET Instance Method Parent Class Static Value : '', currentClass.parent_S_V);
}
}, {
key: ''getStaticVar'',
value: function getStaticVar() {
console.log(''GET Instance Method Parent Class Static Value : '', currentClass.parent_S_V);
return currentClass.parent_S_V;
}
}, {
key: ''area'',
get: function get() {
console.log(''Area : '', this.width * this.height);
return this.width * this.height;
}
}, {
key: ''globalValue'',
get: function get() {
console.log(''GET ID : '', currentClass._staticVar);
return currentClass._staticVar;
},
set: function set(value) {
currentClass._staticVar = value;
console.log(''SET ID : '', currentClass._staticVar);
}
}
];
instanceMethods( currentClass, instanceFunctions );
return currentClass;
}(Shape);
// ===== ES5 Class Conversion Supported Functions =====
function defineProperties(target, props) {
console.log(target, '' : '', props);
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function staticMethods( currentClass, staticProps ) {
defineProperties(currentClass, staticProps);
};
function instanceMethods( currentClass, protoProps ) {
defineProperties(currentClass.prototype, protoProps);
};
function staticVariable( currentClass, staticVariales ) {
// Get Key Set and get its corresponding value.
// currentClass.key = value;
for( var prop in staticVariales ) {
console.log(''Keys : Values'');
if( staticVariales.hasOwnProperty( prop ) ) {
console.log(prop, '' : '', staticVariales[ prop ] );
currentClass[ prop ] = staticVariales[ prop ];
}
}
};
function _inherits(subClass, superClass) {
console.log( subClass, '' : extends : '', superClass );
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype,
{ constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });
if (superClass)
Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
El siguiente fragmento de código es para probar cada instancia tiene su propia copia de miembros de instancia y miembros estáticos comunes.
var objTest = new Rectangle(''Yash_777'', 8, 7);
console.dir(objTest);
var obj1 = new Rectangle(''R_1'', 50, 20);
Rectangle.println(); // Static Method
console.log( obj1 ); // Rectangle {id: "R_1", width: 50, height: 20}
obj1.area; // Area : 1000
obj1.globalValue; // GET ID : 77777
obj1.globalValue = 88; // SET ID : 88
obj1.globalValue; // GET ID : 88
var obj2 = new Rectangle(''R_2'', 5, 70);
console.log( obj2 ); // Rectangle {id: "R_2", width: 5, height: 70}
obj2.area; // Area : 350
obj2.globalValue; // GET ID : 88
obj2.globalValue = 999; // SET ID : 999
obj2.globalValue; // GET ID : 999
console.log(''Static Variable Actions.'');
obj1.globalValue; // GET ID : 999
console.log(''Parent Class Static variables'');
obj1.getStaticVar(); // GET Instance Method Parent Class Static Value : 777
obj1.setStaticVar(7); // SET Instance Method Parent Class Static Value : 7
obj1.getStaticVar(); // GET Instance Method Parent Class Static Value : 7
Las llamadas a métodos estáticos se realizan directamente en la clase y no se pueden llamar en instancias de la clase. Pero puede lograr las llamadas para miembros estáticos desde dentro de una instancia.
Usando la sintaxis:
this.constructor.staticfunctionName();
class MyClass {
constructor() {}
static staticMethod() {
console.log(''Static Method'');
}
}
MyClass.staticVar = 777;
var myInstance = new MyClass();
// calling from instance
myInstance.constructor.staticMethod();
console.log(''From Inside Class : '',myInstance.constructor.staticVar);
// calling from class
MyClass.staticMethod();
console.log(''Class : '', MyClass.staticVar);
Clases de ES6: Las clases de ES2015 son un azúcar simple sobre el patrón de OO basado en prototipos. Tener una única forma declarativa conveniente hace que los patrones de clase sean más fáciles de usar y fomenta la interoperabilidad. Las clases son compatibles con la herencia basada en prototipos, superclasificaciones, métodos de instancia y estáticos y constructores.
Example : referir mi post anterior.
Lo haces a través de un IIFE (expresión de función invocada inmediatamente):
var incr = (function () {
var i = 1;
return function () {
return i++;
}
})();
incr(); // returns 1
incr(); // returns 2
Lo más parecido en JavaScript a una variable estática es una variable global, esto es simplemente una variable declarada fuera del alcance de una función o un objeto literal:
var thisIsGlobal = 1;
function foo() {
var thisIsNot = 2;
}
La otra cosa que podría hacer sería almacenar variables globales dentro de un objeto literal como este:
var foo = { bar : 1 }
Y luego accede a las variables como esta: foo.bar
.
Para condensar todos los conceptos de clase aquí, prueba esto:
var Test = function() {
// "super private" variable, accessible only here in constructor. There are no real private variables
//if as ''private'' we intend variables accessible only by the class that defines the member and NOT by child classes
var test_var = "super private";
//the only way to access the "super private" test_var is from here
this.privileged = function(){
console.log(test_var);
}();
Test.test_var = ''protected'';//protected variable: accessible only form inherited methods (prototype) AND child/inherited classes
this.init();
};//end constructor
Test.test_var = "static";//static variable: accessible everywhere (I mean, even out of prototype, see domready below)
Test.prototype = {
init:function(){
console.log(''in'',Test.test_var);
}
};//end prototype/class
//for example:
$(document).ready(function() {
console.log(''out'',Test.test_var);
var Jake = function(){}
Jake.prototype = new Test();
Jake.prototype.test = function(){
console.log(''jake'', Test.test_var);
}
var jake = new Jake();
jake.test();//output: "protected"
});//end domready
Bueno, otra manera de echar un vistazo a las mejores prácticas en estas cosas, es simplemente ver cómo coffeescript traduce estos conceptos.
#this is coffeescript
class Test
#static
@prop = "static"
#instance
constructor:(prop) ->
@prop = prop
console.log(@prop)
t = new Test(''inst_prop'');
console.log(Test.prop);
//this is how the above is translated in plain js by the CS compiler
Test = (function() {
Test.prop = "static";
function Test(prop) {
this.prop = prop;
console.log(this.prop);
}
return Test;
})();
t = new Test(''inst_prop'');
console.log(Test.prop);
Prueba este:
Si definimos una propiedad y anulamos sus captadores y definidores para usar la propiedad Función Objeto, en teoría, puede tener una variable estática en JavaScript
por ejemplo:
function Animal() {
if (isNaN(this.totalAnimalCount)) {
this.totalAnimalCount = 0;
}
this.totalAnimalCount++;
};
Object.defineProperty(Animal.prototype, ''totalAnimalCount'', {
get: function() {
return Animal[''totalAnimalCount''];
},
set: function(val) {
Animal[''totalAnimalCount''] = val;
}
});
var cat = new Animal();
console.log(cat.totalAnimalCount); //Will produce 1
var dog = new Animal();
console.log(cat.totalAnimalCount); //Will produce 2 and so on.
Puede aprovechar el hecho de que las funciones JS también son objetos, lo que significa que pueden tener propiedades.
Por ejemplo, citando el ejemplo dado en el artículo (ahora desaparecido) Variables estáticas en Javascript :
function countMyself() {
// Check to see if the counter has been initialized
if ( typeof countMyself.counter == ''undefined'' ) {
// It has not... perform the initialization
countMyself.counter = 0;
}
// Do something stupid to indicate the value
alert(++countMyself.counter);
}
Si llama a esa función varias veces, verá que el contador se está incrementando.
Y esta es probablemente una solución mucho mejor que contaminar el espacio de nombres global con una variable global.
Y aquí hay otra solución posible, basada en un cierre: Truco para usar variables estáticas en javascript :
var uniqueID = (function() {
var id = 0; // This is the private persistent value
// The outer function returns a nested function that has access
// to the persistent value. It is this nested function we''re storing
// in the variable uniqueID above.
return function() { return id++; }; // Return and increment
})(); // Invoke the outer function after defining it.
Lo que le da el mismo tipo de resultado, excepto que, esta vez, se devuelve el valor incrementado, en lugar de mostrarse.
Puede crear una variable estática en JavaScript como esta a continuación. Aquí el count
es la variable estática.
var Person = function(name) {
this.name = name;
// first time Person.count is undefined, so it is initialized with 1
// next time the function is called, the value of count is incremented by 1
Person.count = Person.count ? Person.count + 1 : 1;
}
var p1 = new Person(''User p1'');
console.log(p1.constructor.count); // prints 1
var p2 = new Person(''User p2'');
console.log(p2.constructor.count); // prints 2
Puede asignar valores a la variable estática utilizando la función Person
o cualquiera de las instancias:
// set static variable using instance of Person
p1.constructor.count = 10; // this change is seen in all the instances of Person
console.log(p2.constructor.count); // prints 10
// set static variable using Person
Person.count = 20;
console.log(p1.constructor.count); // prints 20
Respuesta actualizada:
En ECMAScript 6 , puede crear funciones estáticas usando la palabra clave static
:
class Foo {
static bar() {return ''I am static.''}
}
//`bar` is a property of the class
Foo.bar() // returns ''I am static.''
//`bar` is not a property of instances of the class
var foo = new Foo()
foo.bar() //-> throws TypeError
Las clases de ES6 no introducen ninguna nueva semántica para las estadísticas. Puedes hacer lo mismo en ES5 así:
//constructor
var Foo = function() {}
Foo.bar = function() {
return ''I am static.''
}
Foo.bar() // returns ''I am static.''
var foo = new Foo()
foo.bar() // throws TypeError
Puede asignar a una propiedad de Foo
porque en las funciones de JavaScript son objetos.
Si desea declarar variables estáticas para crear constantes en su aplicación, entonces encuentro el siguiente como el enfoque más simple.
ColorConstants = (function()
{
var obj = {};
obj.RED = ''red'';
obj.GREEN = ''green'';
obj.BLUE = ''blue'';
obj.ALL = [obj.RED, obj.GREEN, obj.BLUE];
return obj;
})();
//Example usage.
var redColor = ColorConstants.RED;
Si está utilizando la nueva sintaxis de clase , ahora puede hacer lo siguiente:
class MyClass {
static get myStaticVariable() {
return "some static variable";
}
}
console.log(MyClass.myStaticVariable);
aMyClass = new MyClass();
console.log(aMyClass.myStaticVariable, "is undefined");
Esto crea efectivamente una variable estática en JavaScript.
Si proviene de un lenguaje orientado a objetos basado en clases y estático (como Java, C ++ o C #) , asumo que está intentando crear una variable o método asociado a un "tipo" pero no a una instancia.
Un ejemplo que utiliza un enfoque "clásico", con funciones de constructor, podría ayudarlo a captar los conceptos básicos de JavaScript OO:
function MyClass () { // constructor function
var privateVariable = "foo"; // Private variable
this.publicVariable = "bar"; // Public variable
this.privilegedMethod = function () { // Public Method
alert(privateVariable);
};
}
// Instance method will be available to all instances but only load once in memory
MyClass.prototype.publicMethod = function () {
alert(this.publicVariable);
};
// Static variable shared by all instances
MyClass.staticProperty = "baz";
var myInstance = new MyClass();
staticProperty
se define en el objeto MyClass (que es una función) y no tiene nada que ver con sus instancias creadas, JavaScript trata las funciones como objetos de primera clase , por lo que al ser un objeto, puede asignar propiedades a una función.
Si quisieras hacer una variable estática global:
var my_id = 123;
Reemplace la variable con la siguiente:
Object.defineProperty(window, ''my_id'', {
get: function() {
return 123;
},
configurable : false,
enumerable : false
});
puede usar argument.callee para almacenar variables "estáticas" (esto también es útil en la función anónima):
function () {
arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
arguments.callee.myStaticVar++;
alert(arguments.callee.myStaticVar);
}
Entonces, lo que veo con las otras respuestas es que no abordan los requisitos arquitectónicos fundamentales de un atributo estático en la programación orientada a objetos.
La programación orientada a objetos en realidad tiene dos estilos diferentes, uno está ''basado en la clase'' (C ++, C #, Java, etc.), el otro es ''prototypal'' (Javascript). En los lenguajes basados en clases, se supone que un ''atributo estático'' está asociado con la clase y no con los objetos instanciados. Este concepto en realidad funciona de manera mucho más intuitiva en lenguajes prototípicos como Javascript porque simplemente asigna el atributo como un valor del prototipo principal como tal.
function MyObject() {};
MyObject.prototype.staticAttribute = "some value";
Y acceda a él desde cada uno de los objetos que se crean instancias de este constructor como ...
var childObject1 = new MyObject(); // Instantiate a child object
var childObject2 = new MyObject(); // Instantiate another child object
console.log(childObject.staticAttribute); // Access the static Attribute from child 1
console.log(childObject.staticAttribute); // Access the static Attribute from child 2
Ahora, si sigue adelante y cambia, el MyObject.prototype.staticAttribute
cambio caerá en cascada hacia los objetos secundarios que lo heredarán de inmediato.
Sin embargo, hay algunos "errores" que podrían socavar significativamente la naturaleza "estática" de este atributo, o simplemente dejar la vulnerabilidad de seguridad ...
Primero asegúrese de ocultar el constructor del espacio de nombres Global encerrándolo dentro de otra función como el método jQuery ready
$(document).ready(function () {
function MyObject() {
// some constructor instructions
};
MyObject.prototype.staticAttribute = "some value";
var childObject = new MyObject(); // instantiate child object
console.log(childObject.staticAttribute); // test attribute
});
En segundo y último lugar, incluso si lo hace, el atributo aún se puede editar desde cualquiera de las otras partes de su propio script, por lo que podría ocurrir que un error en su código escriba sobre el atributo en uno de los objetos secundarios y se separe es del prototipo principal, por lo que si cambia el atributo principal, dejará de estar en cascada y cambiará el atributo estático del objeto secundario. Ver este jsfiddle. En diferentes escenarios, podríamos Object.freeze(obj)
detener cualquier cambio en el objeto secundario o configurar un método de establecimiento y obtención en el constructor y acceder a un cierre, ambos tienen complejidades asociadas.
Me parece que no hay un análogo perfecto entre la idea basada en la clase de un ''atributo estático'' y esta implementación de Javascript. Así que creo que a la larga podría ser mejor usar un patrón de código diferente que sea más compatible con Javascript. Como un almacén de datos central o caché o incluso un objeto auxiliar dedicado para contener todas las variables estáticas necesarias.
Hay 4 formas de emular variables estáticas de función local en Javascript.
Método 1: uso de propiedades de objeto de función (admitidas en navegadores antiguos)
function someFunc1(){
if( !(''staticVar'' in someFunc1) )
someFunc1.staticVar = 0 ;
alert(++someFunc1.staticVar) ;
}
someFunc1() ; //prints 1
someFunc1() ; //prints 2
someFunc1() ; //prints 3
Método 2: uso de un cierre, variante 1 (compatible con navegadores antiguos)
var someFunc2 = (function(){
var staticVar = 0 ;
return function(){
alert(++staticVar) ;
}
})()
someFunc2() ; //prints 1
someFunc2() ; //prints 2
someFunc2() ; //prints 3
Método 3: uso de un cierre, variante 2 (también compatible con navegadores antiguos)
var someFunc3 ;
with({staticVar:0})
var someFunc3 = function(){
alert(++staticVar) ;
}
someFunc3() ; //prints 1
someFunc3() ; //prints 2
someFunc3() ; //prints 3
Método 4: uso de un cierre, variante 3 (requiere soporte para EcmaScript 2015)
{
let staticVar = 0 ;
function someFunc4(){
alert(++staticVar) ;
}
}
someFunc4() ; //prints 1
someFunc4() ; //prints 2
someFunc4() ; //prints 3
Las variables de nivel de ventana son similares a las estadísticas, en el sentido de que puedes usar referencias directas y están disponibles para todas las partes de tu aplicación
Para variables estáticas privadas, encontré esta manera:
function Class()
{
}
Class.prototype = new function()
{
_privateStatic = 1;
this.get = function() { return _privateStatic; }
this.inc = function() { _privateStatic++; }
};
var o1 = new Class();
var o2 = new Class();
o1.inc();
console.log(o1.get());
console.log(o2.get()); // 2
Si quieres usar prototipo entonces hay una manera
var p = function Person() {
this.x = 10;
this.y = 20;
}
p.prototype.counter = 0;
var person1 = new p();
person1.prototype = p.prototype;
console.log(person1.counter);
person1.prototype.counter++;
var person2 = new p();
person2.prototype = p.prototype;
console.log(person2.counter);
console.log(person1.counter);
¡Al hacerlo, podrá acceder a la variable de contador desde cualquier instancia y cualquier cambio en la propiedad se reflejará de inmediato!
Al trabajar con sitios web de MVC que usan jQuery, me gusta asegurarme de que las acciones AJAX dentro de ciertos controladores de eventos solo se puedan ejecutar una vez que la solicitud anterior haya finalizado. Yo uso una variable de objeto jqXHR "estática" para lograr esto.
Dado el siguiente botón:
<button type="button" onclick="ajaxAction(this, { url: ''/SomeController/SomeAction'' })">Action!</button>
Generalmente uso un IIFE como este para mi controlador de clic:
var ajaxAction = (function (jqXHR) {
return function (sender, args) {
if (!jqXHR || jqXHR.readyState == 0 || jqXHR.readyState == 4) {
jqXHR = $.ajax({
url: args.url,
type: ''POST'',
contentType: ''application/json'',
data: JSON.stringify($(sender).closest(''form'').serialize()),
success: function (data) {
// Do something here with the data.
}
});
}
};
})(null);
No hay tal cosa como una variable estática en Javascript. Este lenguaje está orientado a objetos basados en prototipos, por lo que no hay clases, sino prototipos desde donde los objetos se "copian".
Puede simularlos con variables globales o con prototipos (agregando una propiedad al prototipo):
function circle(){
}
circle.prototype.pi=3.14159
No vi esta idea en ninguna de las respuestas, así que simplemente la agregué a la lista. Si es un duplicado, hágamelo saber y lo eliminaré y le enviaré el otro voto.
He creado una especie de super global en mi sitio web. Como tengo varios archivos js que se cargan en cada carga de página y docenas de otros archivos js que solo se cargan en algunas páginas, pongo toda la función "global" en una sola variable global.
En la parte superior de mi primer archivo "global" incluido está la declaración
var cgf = {}; // Custom global functions.
Luego delcare varias funciones auxiliares globales
cgf.formBehaviors = function()
{
// My form behaviors that get attached in every page load.
}
Luego, si necesito una variable estática, simplemente la guardo fuera del alcance, como fuera del documento, lista o fuera del adjunto de comportamiento. (Yo uso jquery pero debería funcionar en javascript)
cgf.first = true;
$.on(''click'', ''.my-button'', function()
{
// Don''t allow the user to press the submit twice.
if (cgf.first)
{
// first time behavior. such as submit
}
cgf.first = false;
}
Esto, por supuesto, es global, no estático, pero como se reinicializa en cada carga de página, cumple el mismo propósito.
function Person(){
if(Person.count == undefined){
Person.count = 1;
}
else{
Person.count ++;
}
console.log(Person.count);
}
var p1 = new Person();
var p2 = new Person();
var p3 = new Person();