Variables estáticas en JavaScript

716

¿Cómo puedo crear variables estáticas en Javascript?

Rajat
fuente
podemos definir la etiqueta u otra etiqueta html con el atributo de estilo "dispaly: none" y establecer el valor variable para este valor y la operación en este valor. No lo tomemos duro.
asghar
La solución más simple que encontré: no defina ninguna variable estática en la clase. Cuando desee utilizar una variable estática, simplemente defínala allí y luego, por ejemplo someFunc = () => { MyClass.myStaticVariable = 1; }. Luego, simplemente cree un método estático para devolver el miembro estático, por ejemplo static getStatic() { return MyClass.myStaticVariable; }. ¡Entonces puede llamar MyClass.getStatic()desde fuera de la clase para obtener los datos estáticos!
Pixel

Respuestas:

863

Si proviene de un lenguaje orientado a objetos de tipo estático basado en clases (como Java, C ++ o C #) , supongo que está tratando de 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();

staticPropertyestá definido 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.

ACTUALIZACIÓN: ES6 introdujo la capacidad de declarar clases a través de la classpalabra clave. Es el azúcar de sintaxis sobre la herencia existente basada en prototipos.

La staticpalabra clave le permite definir fácilmente propiedades estáticas o métodos en una clase.

Veamos el ejemplo anterior implementado con las clases ES6:

class MyClass {
  // class constructor, equivalent to
  // the function body of a constructor
  constructor() {
    const privateVariable = 'private value'; // Private variable at the constructor scope
    this.publicVariable = 'public value'; // Public property

    this.privilegedMethod = function() {
      // Public Method with access to the constructor scope variables
      console.log(privateVariable);
    };
  }

  // Prototype methods:
  publicMethod() {
    console.log(this.publicVariable);
  }

  // Static properties shared by all instances
  static staticProperty = 'static value';

  static staticMethod() {
    console.log(this.staticProperty);
  }
}

// We can add properties to the class prototype
MyClass.prototype.additionalMethod = function() {
  console.log(this.publicVariable);
};

var myInstance = new MyClass();
myInstance.publicMethod();       // "public value"
myInstance.additionalMethod(); // "public value"
myInstance.privilegedMethod(); // "private value"
MyClass.staticMethod();             // "static value"

CMS
fuente
55
Presumiblemente privilegedMethodno es equivalente a un método privado en OO porque parece que podría llamarse en una instancia de MyClass. ¿Quieres decir que es privilegiado porque puede acceder privateVariable?
Dónal
3
¿No se this.constructorpuede utilizar para acceder a las variables estáticas desde los "métodos de instancia"? En caso afirmativo, vale la pena agregarlo a la respuesta.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
También podría mencionar funciones estáticas en su ejemplo.
David Rodrigues
18
hola, no estoy seguro de estar de acuerdo con esta línea // Variable estática compartida por todas las instancias 'MyClass.staticProperty = "baz";' en cuanto a mí, infiere que puedes encontrar baz de 'myInstance.staticProperty' que, por supuesto, no puedes.
fullstacklife
55
Quizás debería leer MyClass.prototype.staticProperty = "baz";o para ser aún más correcto a los principios de OO, la propiedad estática debería definirse realmente como una función anónima MyClass.prototype.staticProperty = function () {return staticVar;}y para que todas las instancias accedan a una sola variable que también podría modificarse con un setter.
lindsaymacvean
535

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.

Pascal MARTIN
fuente
50
como atajo, podría hacerlo countMyself.counter = countMyself.counter || initial_value;si la variable estática nunca va a ser falsey (cadena falsa, 0, nula o vacía)
Kip
3
Ligeramente más corto y claro: (function () {var id = 0; function uniqueID () {return id ++;};}) ();
Tom Robinson
3
El contador en cierre es muy más rápido que en la clase en Firefox. jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos
Úselo ===para los typeofcontroles, de lo contrario obtendrá una coerción extraña.
Rocío
@SonySantos Su prueba muestra lo contrario para Firefox 40
bartolo-otrit
96

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
khoomeister
fuente
21
Yo diría que esta es la forma más idiomática de hacerlo en JavaScript. Lástima que no reciba demasiados votos a favor gracias a otros métodos que probablemente sean más agradables para las personas que vienen de otros idiomas.
1
Reformularía usando 'cierre' en lugar de solo 'IIFE'.
zendka
39

puede usar argumentos.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);
}
gpilotino
fuente
3
Por lo que puedo entender, este método tiene una ventaja (¿solo una?) Sobre la manera de pascal MARTIN: puede usarlo en funciones anónimas. Un ejemplo de esto sería genial
Dan
27
arguments.calleees obsoleto.
Preguntas de Quolonel
Casi ridiculizo a JS todo el tiempo, pero calleeparecía algo bueno tener. Me pregunto por qué demonios decidieron desaprobar esto ...: |
user2173353
35

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 un código extraído de él, que he modificado para obtener un ejemplo completo que, con suerte, beneficiará 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 las propiedades / funciones estáticas de la siguiente manera:

// access static properties/functions
console.log(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 cierre : la referencia a _somePrivateVariable se mantiene dentro de la función.

Incluso puede definir captadores y establecedores . Eche un vistazo a este fragmento de código (donde destá el prototipo del objeto para el que desea declarar una propiedad, yes 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 a d.yeartravés de gety setfunciones: si no especifica set, entonces la propiedad es de solo lectura y no puede modificarse (tenga en cuenta que no obtendrá un error si intenta configurarlo, pero no tiene ningún efecto). Cada propiedad tiene los atributos writable, configurable(permitir al cambio después de la declaración) y enumerable(permite utilizarlo como empadronador), que son por defecto false. Puede configurarlos definePropertyen 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 legible / grabable a, una propiedad de solo lectura by una propiedad de solo escritura c, a través de la cual ase puede acceder a la propiedad .

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 newpalabra 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 instancias siguientes funcionarán como se esperaba:

var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast();     // you can omit the new keyword because of the helper

La declaración 'nuevo' 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 utilizar la returninstrucción en la función de constructor Podcastpara devolver un objeto personalizado que protege las funciones de las que depende internamente la clase pero que necesitan ser expuestas. Esto se explica más adelante en el capítulo 2 (Objetos) de la serie de artículos.

Puedes decir eso ay bheredar de Podcast. Ahora, ¿qué sucede si desea agregar un método a Podcast que se aplique a todos ellos después ay bhaya sido instanciado? En este caso, use lo .prototypesiguiente:

Podcast.prototype.titleAndLink = function() {
    return this.title + " [" + this.link + "]";
};

Ahora llame ay botra vez:

console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"

Puede encontrar más detalles sobre los prototipos aquí . Si desea hacer más herencia, le sugiero que investigue esto .


Se recomienda encarecidamente leer la serie de artículos que he mencionado anteriormente , que incluyen también los siguientes temas:

  1. Las funciones
  2. Objetos
  3. Prototipos
  4. Hacer cumplir nuevas funciones de constructor
  5. Elevación
  6. Inserción automática de punto y coma
  7. Propiedades y métodos estáticos

Tenga en cuenta que la "característica" de inserción automática de punto y coma de JavaScript (como se menciona en 6.) a menudo es responsable de causar problemas extraños en su código. Por lo tanto, prefiero considerarlo como un error que como una característica.

Si desea leer más, aquí hay un artículo de MSDN bastante interesante sobre estos temas, algunos de ellos descritos 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 outparámetros de C # (como en DateTime.TryParse(str, out result)) en JavaScript, puede encontrar el código de muestra aquí.


Aquellos de ustedes que están trabajando con IE (que no tiene consola para JavaScript a menos que abra las herramientas de desarrollador usando F12y abra la pestaña de la consola) pueden encontrar útil el siguiente fragmento. Le permite usar console.log(msg);como se usa en los ejemplos anteriores. Simplemente insértelo antes de la Podcastfunción.

Para su comodidad, aquí está el código anterior en un fragmento de código único completo:


Notas:

  • Algunos buenos consejos, sugerencias y recomendaciones sobre la programación de JavaScript en general se pueden encontrar aquí (prácticas recomendadas de JavaScript) y allí ('var' versus 'let') . También se recomienda este artículo sobre los tipos de letra implícitos (coerción) .

  • Una forma conveniente de usar clases y compilarlas en JavaScript es TypeScript. Aquí hay un patio de juegos donde puedes encontrar algunos ejemplos que te 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 "Uso de clases", "Uso de herencia" y "Uso de genéricos" seleccionándolos en el cuadro combinado: estas son plantillas agradables que puede usar instantáneamente en JavaScript. La mecanografía se usa con Angular.

  • 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:&nbsp;</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 del script en un *.jsarchivo separado ; esto solo está escrito en línea para mantener el ejemplo corto.

Las funciones de auto invocación (también conocidas como IIFE = Expresión de función invocada inmediatamente) se describen con más detalle aquí .

Mate
fuente
28
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();
jim_zike_huang
fuente
28

Respuesta actualizada:

En ECMAScript 6 , puede crear funciones estáticas usando la staticpalabra clave:

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 semántica nueva 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 Fooporque en JavaScript las funciones son objetos.

Max Heiber
fuente
Foo.bar;devuelve la función asignada a él, no la cadena devuelta por la función como su comentario implica.
¿Puede agregar alguna información sobre cómo establecer (sobrescribir) un valor estático en esos dos ejemplos?
Marchitez
1
@Wilt en ambos casos, una propiedad "estática" es solo una propiedad de la función, por lo que debe configurarla y sobrescribirla como lo haría con cualquier otra propiedad en JavaScript. En ambos casos, se puede establecer la barpropiedad de Fooque 3desea:Foo.bar = 3;
Max Heiber
Pregunta específica de ES6: stackoverflow.com/questions/28445693/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
16

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 Personconstructor en este ejemplo tiene acceso al nombre de la variable privada, al igual que los métodos getName()y setName(). Con este patrón, la variable de nombre se vuelve estática y se usará entre todas las instancias. Esto significa que llamar setName()a una instancia afecta a todas las demás instancias. Llamar setName()o crear una nueva Personinstancia establece la variable de nombre en un nuevo valor. Esto hace que todas las instancias devuelvan el mismo valor.

Nate
fuente
se ve constructor + prototipo (híbrido)
Ganesh Kumar
2
Esto coloca el objeto Persona en el espacio de nombres global. No es una solución que recomendaría.
Ghola
No creo que esta sea una verdadera variable estática porque se instancia de manera diferente con cada nuevo objeto. ¿Un objeto estático debe ser coherente en todos los objetos que heredan del prototipo principal?
lindsaymacvean
1
@Ghola La intención aquí era explicar cómo crear una variable estática. El espacio de nombres adecuado y evitar los globales es un tema separado que puede haber agregado a la complejidad de la respuesta. Depende del usuario determinar cómo adjuntar el constructor sin contaminar. Si es lo suficientemente bueno para Nicholas Zakas, es lo suficientemente bueno para mí.
Nate
@lindsaymacvean Es una variable estática porque el valor único se comparte en todas las instancias. Está bien que cambie el valor. Si una instancia cambia el valor, todas las instancias se verán afectadas. No es probable que se use exactamente igual que en el ejemplo anterior. Permitir que el valor se establezca durante la creación de instancias es solo para mostrar que es posible. Un caso de uso más probable sería tener solo el getter y setter o al menos verificar para asegurarse de que esté configurado en algo diferente a indefinido.
Nate
15

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.

Automatico
fuente
¡Esto es útil al construir clases de utilidad estáticas!
Intrusión
1
Pero ahora la pregunta es cómo persiste un valor y permite cambios con un setter. Sería necesario un cierre o una propiedad MyClassdefinida fuera del constructo de la clase.
Trincot
Relacionado: stackoverflow.com/questions/28445693/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
8

Si desea declarar variables estáticas para crear constantes en su aplicación, encontré lo siguiente como el enfoque más simplista

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;
Hemant
fuente
8

Sobre el classpresentado por ECMAScript 2015. Las otras respuestas no son totalmente claras.

Aquí hay un ejemplo que muestra cómo crear una var estática staticVarcon ClassName. varsintaxis:

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, utilizamos la .constructorpropiedad que devuelve una referencia a la función de constructor 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
Bobina
fuente
7

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;
  };
})();
funroll
fuente
7

Además del resto, actualmente hay un borrador (propuesta de etapa 2 ) sobre las propuestas de ECMA que introduce static los campos públicos en las clases. ( se consideraron campos privados )

Usando el ejemplo de la propuesta, la staticsintaxis propuesta se verá así:

class CustomDate {
  // ...
  static epoch = new CustomDate(0);
}

y ser equivalente a lo siguiente que otros han destacado:

class CustomDate {
  // ...
}
CustomDate.epoch = new CustomDate(0);

Luego 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 característica con el complemento de propiedades de clase de transformación que puede usar. Además, aunque todavía está en progreso, lo V8está implementando .

Dimitris Fasarakis Hilliard
fuente
6

Puede crear una variable estática en JavaScript como esta a continuación. Aquí countestá 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 Personfunción 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
Sнаđошƒаӽ
fuente
Este es uno de los buenos enfoques para declarar variables estáticas y acceder a ellas en JavaScript.
ArunDhwaj IIITH
5

Si desea 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
});
JoolzCheat
fuente
4

Lo más parecido en JavaScript a una variable estática es una variable global; esta es simplemente una variable declarada fuera del alcance de una función u 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 acceder a la variabels como esto: foo.bar.

Andrew Hare
fuente
este me ayudó a subir varios archivos ..... var foo = {counter: 1}; function moreFiles () {fileName = "File" + foo.counter; foo.counter = foo.counter + 1;
veer7
4

Para condensar todos los conceptos de clase aquí, pruebe 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 forma de echar un vistazo a las mejores prácticas en estas cosas es 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);
Luca Reghellin
fuente
4

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
. Imprimirá 1,2,3, etc.

Kerim
fuente
2
Ese es un caso diferente. Su ejemplo es sobre ámbitos.
Challenget
4

Hay otro enfoque, que resolvió mis requisitos después de navegar por este hilo. Depende exactamente de lo que quiera 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 durante un período indefinido más largo hasta que se borre 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, la vida útil, la semántica, la dinámica, etc. de las variables globales de nivel superior, es decir, Window.myglobal. No sé cuán eficiente es, pero eso no es importante para cantidades modestas de datos, a las que se accede a tasas modestas.

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 a O'Reilly Safaribooks (vale su peso en oro).

Greg E
fuente
2

La función / classes permite solo un constructor único para su alcance de objeto. Function Hoisting, declarations & expressions

  • Las funciones creadas con el constructor de funciones no crean cierres a 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)

Cierres : las copias del cierre funcionan con datos conservados.

  • Las copias de cada cierre se crean para una función con sus propios valores o referencias libres. Cada vez que usa una función dentro de otra función, se usa un cierre.
  • Un cierre en JavaScript es como mantener una copia de todas las variables locales de su función principal mediante innerFunctions.

      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 pueda comprender fácilmente las clases de funciones.

'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 que 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 realizar las llamadas para miembros estáticos desde dentro de una instancia.

Usando 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 ES6: Las clases ES2015 son un simple azúcar sobre el patrón 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 admiten herencia basada en prototipos, super llamadas, instancias y métodos y constructores estáticos.

Ejemplo : consulte mi publicación anterior.

Yash
fuente
2

Hay 4 formas de emular variables estáticas locales de función en Javascript.

Método 1: uso de propiedades de objeto de función (admitido 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
Liberarse
fuente
2

Puede definir funciones estáticas en JavaScript utilizando la staticpalabra clave:

class MyClass {
  static myStaticFunction() {
    return 42;
  }
}

MyClass.myStaticFunction(); // 42

Al momento de escribir esto, aún no puede definir propiedades estáticas (que no sean funciones) dentro de la clase. Las propiedades estáticas siguen siendo una propuesta de Etapa 3 , lo que significa que aún no forman parte de JavaScript. Sin embargo, no hay nada que le impida simplemente asignar a una clase como lo haría a cualquier otro objeto:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

Nota final: tenga cuidado con el uso de objetos estáticos con herencia: todas las clases heredadas comparten la misma copia del objeto .

vkarpov15
fuente
1

En JavaScript, no hay término o palabra clave estática, pero podemos poner 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
Satyapriya Mishra
fuente
1

Uso muchas variables de función estática y es una verdadera lástima que JS no tenga un mecanismo incorporado para eso. Demasiado a menudo veo código donde las variables y funciones se definen en un ámbito externo a pesar de que solo se usan dentro de una función. Esto es feo, propenso a errores y solo busca problemas ...

Se me ocurrió el siguiente método:

if (typeof Function.prototype.statics === 'undefined') {
  Function.prototype.statics = function(init) {
    if (!this._statics) this._statics = init ? init() : {};
    return this._statics;
  }
}

Esto agrega un método 'estático' a todas las funciones (sí, simplemente relájese), cuando se lo llame, agregará un objeto vacío (_statics) al objeto de función y lo devolverá. Si se proporciona una función init, _statics se establecerá en el resultado init ().

Entonces puedes hacer:

function f() {
  const _s = f.statics(() => ({ v1=3, v2=somefunc() });

  if (_s.v1==3) { ++_s.v1; _s.v2(_s.v1); }
} 

Comparando esto con un IIFE, que es la otra respuesta correcta, tiene la desventaja de agregar una asignación y una en cada llamada de función y agregar un miembro '_ estático' a la función, sin embargo, hay algunas ventajas: los argumentos están ahí la parte superior no está en la función interna, el uso de un 'estático' en el código de la función interna es explícito con un '_s'. prefijo, y en general es más simple de ver y entender.

kofifus
fuente
1

Resumen:

En ES6/ ES 2015, la classpalabra clave se introdujo con una staticpalabra clave acompañada . Tenga en cuenta que este es el azúcar sintáctico sobre el modelo de herencia prototípica que encarna javavscript. La staticpalabra clave funciona de la siguiente manera para los métodos:

class Dog {

  static bark () {console.log('woof');}
  // classes are function objects under the hood
  // bark method is located on the Dog function object
  
  makeSound () { console.log('bark'); }
  // makeSound is located on the Dog.prototype object

}

// to create static variables just create a property on the prototype of the class
Dog.prototype.breed = 'Pitbull';
// So to define a static property we don't need the `static` keyword.

const fluffy = new Dog();
const vicky = new Dog();
console.log(fluffy.breed, vicky.breed);

// changing the static variable changes it on all the objects
Dog.prototype.breed = 'Terrier';
console.log(fluffy.breed, vicky.breed);

Willem van der Veen
fuente
2
Estaba pidiendo una variable estática, no una función estática.
Konrad Höffner
1

Usé el prototipo y así funcionó:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }
}

Cat.COLLECTION_NAME = "cats";

o usando un captador estático:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }

  static get COLLECTION_NAME() {
    return "cats"
  }
}
EliuX
fuente
0

Los niveles de ventana son más o menos como estáticos en el sentido de que puede usar referencias directas y están disponibles para todas las partes de su aplicación

Bostone
fuente
3
Una descripción mucho mejor de tales variables es 'global', en lugar de estática.
Patrick M
0

No existe 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
Gerardo
fuente
Este método funciona, pero estás contaminando elFunction.prototype
Dan
@Dan: Tengo entendido que esto sería solo para círculo y no para Función. Al menos eso es lo que Chrome intenta decirme: function circle() {}| circle.prototypeEl | circle.prototype.pi = 3.14El | circle.prototypeEl | Function.prototypeEl | Function.__proto__(si eso es lo que querías decir)
Aktau
0

Al trabajar con sitios web de MVC que usan jQuery, me gusta asegurarme de que las acciones de AJAX dentro de ciertos controladores de eventos solo se puedan ejecutar una vez que se haya completado la solicitud anterior. Utilizo 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 clics:

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);
Todd L
fuente
0

Si quieres usar un 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 hacer esto, podrá acceder a la variable de contador desde cualquier instancia y cualquier cambio en la propiedad se reflejará de inmediato!

Charlie
fuente