web-dev-qa-db-fra.com

Variables statiques en JavaScript

Comment créer des variables statiques en Javascript?

640
Rajat

Si vous venez d'un langage orienté objet, basé sur les classes et typé statiquement (tel que Java, C++ ou C #), je suppose que vous essayez de créer une variable ou une méthode associée à un "type" mais pas à une instance .

Un exemple utilisant une approche "classique", avec des fonctions de constructeur, pourrait peut-être vous aider à comprendre les concepts de JavaScript OO de base:

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 est défini dans l'objet MyClass (qui est une fonction) et n'a rien à voir avec ses instances créées. JavaScript traite les fonctions comme objets de première classe , vous pouvez donc affecter des propriétés à une fonction.

810
CMS

Vous pouvez tirer parti du fait que les fonctions JS sont également des objets, ce qui signifie qu'elles peuvent avoir des propriétés.

Par exemple, citons l'exemple donné dans l'article (maintenant disparu)/ Variables statiques 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 vous appelez cette fonction plusieurs fois, vous verrez que le compteur est en cours d'incrémentation.

Et c'est probablement une bien meilleure solution que de polluer l'espace de noms global avec une variable globale.


Et voici une autre solution possible, basée sur une fermeture: Astuce pour utiliser des variables statiques 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.

Ce qui vous donne le même genre de résultat - sauf que, cette fois, la valeur incrémentée est renvoyée au lieu d’être affichée.

513
Pascal MARTIN

Vous le faites via un IIFE (expression de fonction immédiatement appelée):

var incr = (function () {
    var i = 1;

    return function () {
        return i++;
    }
})();

incr(); // returns 1
incr(); // returns 2
81
khoomeister

vous pouvez utiliser arguments.callee pour stocker des variables "statiques" (cela est également utile dans les fonctions anonymes):

function () {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
  arguments.callee.myStaticVar++;
  alert(arguments.callee.myStaticVar);
}
39
gpilotino

J'ai déjà vu quelques réponses similaires, mais j'aimerais mentionner que cet article le décrit le mieux, alors j'aimerais le partager avec vous.

En voici un extrait du code que j'ai modifié pour obtenir un exemple complet qui, espérons-le, profite à la communauté car il peut être utilisé comme modèle de conception pour les classes.

Il répond également à votre question:

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 + ' ...');
};

Étant donné cet exemple, vous pouvez accéder aux propriétés/fonctions statiques comme suit:

// access static properties/functions
Podcast.FILE_EXTENSION;                // 'mp3'
Podcast.download('Astronomy cast');    // 'Downloading Astronomy cast ...'

Et les propriétés/fonctions de l'objet simplement comme:

// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString());       // Title: The Simpsons
console.log(podcast.immutableProp());  // 123

Notez que dans podcast.immutableProp (), nous avons un fermeture : La référence à _somePrivateVariable est conservée à l'intérieur de la fonction .

Vous pouvez même définir des getters et des setters . Jetez un coup d'œil à cet extrait de code (où dest le prototype de l'objet pour lequel vous souhaitez déclarer une propriété, yest une variable privée non visible en dehors du constructeur):

// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
    get: function() {return this.getFullYear() },
    set: function(y) { this.setFullYear(y) }
});

Il définit la propriété d.year via les fonctions getet set- si vous ne spécifiez pas setname__, la propriété est en lecture seule et ne peut pas être modifiée (sachez que vous n'obtiendrez pas d'erreur si vous essayez de la définir, mais elle n'aura pas effet). Chaque propriété a les attributs writablename__, configurable(autoriser à changer après la déclaration) et enumerable(autoriser à l'utiliser comme énumérateur), qui sont par défaut falsename__. Vous pouvez les définir via definePropertydans le 3ème paramètre, par exemple. enumerable: true.

Ce qui est également valide est cette syntaxe:

// getters and setters - alternative syntax
var obj = { a: 7, 
            get b() {return this.a + 1;}, 
            set c(x) {this.a = x / 2}
        };

qui définit une propriété lisible/réinscriptible aname__, une propriété en lecture seule bet une propriété en écriture seule cname__, via laquelle la propriété aest accessible.

Utilisation:

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

Notes:

Pour éviter tout comportement inattendu au cas où vous auriez oublié le mot clé newname__, je vous suggère d'ajouter les éléments suivants à la fonction Podcastname__:

// instantiation helper
function Podcast() {
    if(false === (this instanceof Podcast)) {
        return new Podcast();
    }
// [... same as above ...]
};

Maintenant, les deux instanciations suivantes fonctionneront comme prévu:

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

La nouvelle instruction crée un nouvel objet et copie toutes les propriétés et méthodes, c.-à-d.

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"

Notez également que dans certaines situations, il peut être utile d'utiliser l'instruction returndans la fonction constructeur Podcastpour renvoyer un objet personnalisé protégeant les fonctions sur lesquelles la classe s'appuie en interne mais qui doivent être exposées. Ceci est expliqué plus en détail au chapitre 2 (Objets) de la série d'articles.

Vous pouvez dire que aet bhéritent de Podcastname__. Maintenant, que se passe-t-il si vous souhaitez ajouter une méthode au podcast qui s'applique à tous après que aet baient été instanciés? Dans ce cas, utilisez le .prototype comme suit:

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

Appelez à nouveau aet bname__:

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

Vous pouvez trouver plus de détails sur les prototypes ici . Si vous voulez faire plus d'héritage, je suggère de regarder dans this .


Les séries d'articles que j'ai mentionnées ci-dessus sont hautement recommandées à lire, elles incluent également les sujets suivants:

  1. Les fonctions
  2. Objets
  3. Prototypes
  4. Application des nouvelles fonctions du constructeur
  5. Levage
  6. Insertion automatique de point-virgule
  7. Propriétés et méthodes statiques

Notez que le insertion automatique d'un point-virgule "la fonctionnalité" de JavaScript (comme indiqué en 6.) est très souvent responsable de causer des problèmes étranges dans votre code. Par conséquent, je préférerais le considérer comme un bug que comme une fonctionnalité.

Si vous voulez en savoir plus, ici est un article assez intéressant de MSDN sur ces sujets, certains d'entre eux décrits fournissent encore plus de détails.

Ce qui est intéressant à lire aussi (couvrant également les sujets mentionnés ci-dessus) sont ces articles du Guide JavaScript MDN :

Si vous voulez savoir émuler des paramètres c # out (comme dans DateTime.TryParse(str, out result)) en JavaScript, vous pouvez trouver exemple de code ici.


Ceux d’entre vous qui travaillent avec IE (qui n’a pas de console pour JavaScript sauf si vous ouvrez les outils de développement avec F12 et ouvrez l'onglet de la console) pourrait trouver l'extrait suivant utile. Cela vous permet d'utiliser console.log(msg); comme dans les exemples ci-dessus. Il suffit de l'insérer avant la fonction Podcastname__.

Pour votre commodité, voici le code ci-dessus dans un extrait de code unique:

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>

Notes:

  • Quelques bons conseils, astuces et recommandations sur la programmation JavaScript en général, vous pouvez trouver ici (bonnes pratiques JavaScript) et là-bas ( 'var' versus 'let'). Cet article est également recommandé à propos des typecasts implicites (contrainte).

  • Un moyen pratique d’utiliser des classes et de les compiler dans JavaScript est TypeScript. Voici un terrain de jeu où vous pouvez en trouver. des exemples vous montrant comment cela fonctionne. Même si vous n'utilisez pas TypeScript pour le moment, vous pouvez jeter un coup d'œil car vous pouvez comparer TypeScript au résultat JavaScript dans une vue côte à côte. La plupart des exemples sont simples, mais il existe également un exemple Raytracer que vous pouvez essayer instantanément. Je recommande en particulier de rechercher les exemples "Utilisation des classes", "Utilisation de l'héritage" et "Utilisation des génériques" en les sélectionnant dans la liste déroulante - il s'agit de modèles Nice que vous pouvez utiliser instantanément en JavaScript. TypeScript est utilisé avec Angular.

  • Pour réaliser l'encapsulation des variables locales, des fonctions, etc. en JavaScript, je suggère d'utiliser un modèle comme celui-ci (JQuery utilise la même technique):

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

Bien sûr, vous pouvez - et devriez - placer le code de script dans un fichier *.js séparé; ceci est juste écrit en ligne pour garder l'exemple court.

28
Matt
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();
27
jim_zike_huang

Réponse mise à jour:

Dans ECMAScript 6 , vous pouvez créer des fonctions statiques à l'aide du mot clé 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

Les classes ES6 n'introduisent aucune nouvelle sémantique pour la statique. Vous pouvez faire la même chose dans ES5 comme ceci:

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

Vous pouvez affecter une propriété de Foo car les fonctions JavaScript sont des objets.

22
Max Heiber

L'exemple et l'explication suivants sont tirés du livre Professional JavaScript for Web Developers 2nd Edition de Nicholas Zakas. C’est la réponse que je cherchais donc j’ai pensé qu’il serait utile de l’ajouter ici.

(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

Le constructeur Person de cet exemple a accès au nom de variable privée, de même que les méthodes getName() et setName(). En utilisant ce modèle, la variable de nom devient statique et sera utilisée parmi toutes les instances. Cela signifie que l'appel de setName() sur une instance affecte toutes les autres instances. L'appel de setName() ou la création d'une nouvelle instance Person définit la variable name avec une nouvelle valeur. Cela provoque toutes les instances pour renvoyer la même valeur.

16
Nate

Si vous utilisez la nouvelle syntaxe class , vous pouvez maintenant procéder comme suit:

    class MyClass {
      static get myStaticVariable() {
        return "some static variable";
      }
    }

    console.log(MyClass.myStaticVariable);

    aMyClass = new MyClass();
    console.log(aMyClass.myStaticVariable, "is undefined");

Cela crée effectivement une variable statique en JavaScript.

10
Automatico

Si vous voulez déclarer des variables statiques pour la création de constantes dans votre application, je trouve que suivre comme approche la plus simpliste

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

À propos de class introduit par ECMAScript 2015. Les autres réponses ne sont pas tout à fait claires.

Voici un exemple montrant comment créer une variable statique staticVar avec la variable 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

Pour accéder à la variable statique, nous utilisons la propriété .constructor qui renvoie une référence à la fonction de constructeur d'objet ayant créé la classe . Nous pouvons l'appeler sur les deux instances créées:

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
7
COil

Il y a d'autres réponses similaires, mais aucune d'entre elles ne m'a tout à fait plu. Voici ce que j'ai fini avec:

var nextCounter = (function () {
  var counter = 0;
  return function() {
    var temp = counter;
    counter += 1;
    return temp;
  };
})();
6
funroll

Vous pouvez créer une variable statique en JavaScript comme ceci ci-dessous. Ici count est la variable statique.

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

Vous pouvez affecter des valeurs à la variable statique à l'aide de la fonction Person ou de l'une des instances suivantes:

// 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
6
Sнаđошƒаӽ

Si vous voulez créer une variable statique globale:

var my_id = 123;

Remplacez la variable par le suivant:

Object.defineProperty(window, 'my_id', {
    get: function() {
            return 123;
        },
    configurable : false,
    enumerable : false
});
5
JoolzCheat

Les variables JavaScript sont static par défaut. Exemple:

var x = 0;

function draw() {
    alert(x); //
    x+=1;
}

setInterval(draw, 1000);

La valeur de x est incrémentée de 1 toutes les 1000 millisecondes
Il imprimera 1,2,3 etc.

5
Kerim

Pour condenser tous les concepts de classe ici, testez ceci:

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

Une autre façon d’examiner les meilleures pratiques dans ce domaine consiste simplement à voir comment coffeescript traduit ces concepts.

#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);
4
Luca Reghellin

Une autre approche a permis de résoudre mes besoins après avoir parcouru ce fil de discussion. Cela dépend de ce que vous voulez réaliser avec une "variable statique".

La propriété globale sessionStorage ou localStorage permet de stocker les données pendant la durée de la session ou pendant une période indéfinie plus longue, jusqu'à ce qu'elles soient explicitement effacées, respectivement. Cela permet aux données d'être partagées entre toutes les fenêtres, cadres, panneaux d'onglets, fenêtres contextuelles, etc. de votre page/application et est beaucoup plus puissant qu'une simple "variable statique/globale" dans un segment de code.

Il évite tous les problèmes liés à la portée, à la durée de vie, à la sémantique, à la dynamique, etc. des variables globales de niveau supérieur, telles que Window.myglobal. Je ne sais pas à quel point c'est efficace, mais ce n'est pas important pour de petites quantités de données auxquelles on accède à des taux modestes.

Facilement accessible en tant que "sessionStorage.mydata = rien" et récupéré de la même manière. Voir "JavaScript: Le guide définitif, sixième édition", David Flanagan, ISBN: 978-0-596-80552-4, chapitre 20, section 20.1. Ceci est facilement téléchargeable en tant que PDF par simple recherche, ou dans votre abonnement O'Reilly Safaribooks (qui vaut son pesant d'or).

4
Greg E

La chose la plus proche en JavaScript d’une variable statique est une variable globale - c’est simplement une variable déclarée en dehors de la portée d’un littéral de fonction ou d’objet:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

L'autre chose que vous pourriez faire serait de stocker des variables globales dans un objet littéral comme ceci:

var foo = { bar : 1 }

Et puis accéder aux variables comme ceci: foo.bar.

4
Andrew Hare

En plus du reste, il existe actuellement un brouillon ( proposition de stade 2 ) sur Propositions ECMA qui introduit les champs staticpublic dans les classes. ( les champs privés ont été considérés )

En utilisant l'exemple de la proposition, la syntaxe static proposée se présentera comme suit: 

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

et être équivalent à ce que d'autres ont souligné: 

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

Vous pouvez ensuite y accéder via CustomDate.Epoch.

Vous pouvez suivre la nouvelle proposition dans proposal-static-class-features


Actuellement, babel supporte cette fonctionnalité avec le plugin propriétés de la classe de transformation } que vous pouvez utiliser. De plus, bien que toujours en cours, V8 l'implémente } _. 

3

Il existe 4 façons d'émuler des variables statiques locales à fonctions javascript.

Méthode 1: utilisation des propriétés de l'objet fonction (pris en charge par les anciens navigateurs)

function someFunc1(){
    if( !('staticVar' in someFunc1) )
        someFunc1.staticVar = 0 ;
    alert(++someFunc1.staticVar) ;
}

someFunc1() ; //prints 1
someFunc1() ; //prints 2
someFunc1() ; //prints 3

Méthode 2: utilisation d'une fermeture, variante 1 (prise en charge par les anciens navigateurs)

var someFunc2 = (function(){
    var staticVar = 0 ;
    return function(){
        alert(++staticVar) ;
    }
})()

someFunc2() ; //prints 1
someFunc2() ; //prints 2
someFunc2() ; //prints 3

Méthode 3: utilisation d'une fermeture, variante 2 (également pris en charge par les anciens navigateurs)

var someFunc3 ;
with({staticVar:0})
    var someFunc3 = function(){
        alert(++staticVar) ;
    }

someFunc3() ; //prints 1
someFunc3() ; //prints 2
someFunc3() ; //prints 3

Méthode 4: utilisation d'une fermeture, variante 3 (nécessite la prise en charge d'EcmaScript 2015)

{
    let staticVar = 0 ;
    function someFunc4(){
        alert(++staticVar) ;
    }
}

someFunc4() ; //prints 1
someFunc4() ; //prints 2
someFunc4() ; //prints 3
1
GetFree

La fonction/classes n'autorise qu'un seul constructeur pour sa portée d'objet . Function Hoisting, declarations & expressions

  • Les fonctions créées avec le constructeur Function ne créent pas de fermetures dans leurs contextes de création; ils sont toujours créés dans la portée globale.

      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)
    

Fermetures - Les copies de fermetures fonctionnent avec des données préservées.

  • Les copies de chaque fermeture sont créées dans une fonction avec leurs propres valeurs libres ou références. Chaque fois que vous utilisez une fonction dans une autre fonction, une fermeture est utilisée.
  • Une fermeture en JavaScript revient à conserver une copie de toutes les variables locales de sa fonction parente par 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
    

ES5 Classes de fonctions: utilise Object.defineProperty (O, P, Attributs)

La méthode Object.defineProperty () définit une nouvelle propriété directement sur un objet ou modifie une propriété existante sur un objet et renvoie l'objet.

Créé des méthodes en utilisant `` , de sorte que chacun puisse facilement comprendre les classes de fonctions.

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

L'extrait de code ci-dessous doit être testé environ. Chaque instance a sa propre copie des membres de l'instance et des membres statiques communs.

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

Méthode statique les appels sont effectués directement sur la classe et ne sont pas appelables sur les instances de la classe. Mais vous pouvez réaliser les appels pour les membres statiques à partir d'une instance.

En utilisant la syntaxe:

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

Classes ES6: Les classes ES2015 sont un simple sucre par rapport au modèle OO basé sur un prototype. Le fait de disposer d’un seul formulaire déclaratif pratique facilite l’utilisation des modèles de classe et encourage l’interopérabilité. Les classes prennent en charge l'héritage, les super appels, les méthodes d'instance, les méthodes statiques et les constructeurs basés sur des prototypes.

Exemple : référez-vous à mon précédent post.

1
Yash

En JavaScript, il n'y a pas de terme ou de mot clé statique, mais nous pouvons placer ces données directement dans un objet function (comme dans tout autre objet).

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
1
Satyapriya Mishra

Si vous voulez utiliser un prototype, alors il y a un moyen

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

En faisant cela, vous pourrez accéder à la variable counter de n'importe quelle instance et tout changement dans la propriété sera immédiatement répercuté !!

0
charlie

Essaye celui-là:

Si nous définissons une propriété et que nous substituons ses getters et ses setters à l'utilisation de la propriété Function Object, alors en théorie, vous pouvez avoir une variable statique en javascript.

par exemple:

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.

0
user2959417

J'utilise beaucoup les variables de fonction statiques et c'est vraiment dommage. JS n'a pas de mécanisme intégré pour cela. Trop souvent, je vois du code dans lequel des variables et des fonctions sont définies dans une portée externe, même si elles sont simplement utilisées dans une fonction. C'est moche, sujet aux erreurs et juste demander des ennuis ...

Je suis venu avec la méthode suivante:

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

Cela ajoute une méthode 'statique' à toutes les fonctions (oui, détendez-vous), son appel ajoutera un objet vide (_statics) à l'objet fonction et le renverra. Si une fonction init est fournie, _statics sera défini sur le résultat init ().

Vous pouvez alors faire:

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

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

En comparant cela à un IIFE qui est l’autre bonne réponse, cela présente l’inconvénient d’ajouter une affectation et une si à chaque appel de fonction et d’ajouter un membre '_statics' à la fonction. Cependant, il existe quelques avantages: les arguments sont présents à le haut ne se trouvant pas dans la fonction interne, l'utilisation d'un 'statique' dans le code de la fonction interne est explicite avec un '_s.' préfixe, et il est globalement plus simple à regarder et à comprendre.

0
kofifus

Donc, ce que je vois avec les autres réponses, c'est qu'elles ne répondent pas à l'exigence architecturale fondamentale d'un attribut statique dans la programmation orientée objet. 

La programmation orientée objet a en réalité deux styles différents: l’un est «basé sur les classes» (C++, C #, Java, etc.), l’autre est «prototypal» (Javascript). Dans les langages basés sur les classes, un "attribut statique" est supposé être associé à la classe et non aux objets instanciés. Ce concept fonctionne de manière beaucoup plus intuitive dans un langage prototype tel que Javascript, car vous attribuez simplement l'attribut à une valeur du prototype parent.

function MyObject() {};
MyObject.prototype.staticAttribute = "some value";

Et y accéder à partir de chacun des objets instanciés à partir de ce constructeur comme si ...

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

Maintenant, si vous continuez et changez le MyObject.prototype.staticAttribute, le changement se répercutera sur les objets enfants qui en hériteront immédiatement. 

Cependant, il existe quelques "pièges" qui pourraient miner de manière significative la nature "statique" de cet attribut, ou simplement laisser une vulnérabilité de sécurité ... 

Tout d’abord, assurez-vous de masquer le constructeur de l’espace de nom global en l’enfermant dans une autre fonction, telle que la méthode 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
});

Deuxièmement et enfin, même si vous faites cela, l’attribut est toujours éditable à partir de l’une des autres parties de votre propre script. Il est donc possible qu’un bogue dans votre code écrive sur l’attribut sur l’un des objets enfants et le détache. à partir du prototype parent. Par conséquent, si vous modifiez l'attribut parent, il ne sera plus mis en cascade et ne modifiera pas l'attribut statique de l'objet enfant. Voir ce jsfiddle. Dans différents scénarios, nous pourrions soit Object.freeze(obj) pour arrêter toute modification de l'objet enfant, soit configurer une méthode setter et getter dans le constructeur et accéder à une fermeture, ces deux opérations étant associées à des complexités.

Il me semble qu'il n'y a pas d'analogue parfait entre l'idée d'un «attribut statique» basée sur les classes et cette implémentation Javascript. Je pense donc qu’il serait peut-être préférable, à long terme, d’utiliser un modèle de code différent, plus compatible avec Javascript. Comme un magasin de données central ou un cache ou même un objet d'assistance dédié pour contenir toutes les variables statiques nécessaires. 

0
lindsaymacvean

Résumé:

Dans ES6/ES 2015, le mot clé class a été introduit avec un mot clé static accompagné. N'oubliez pas qu'il s'agit d'un sucre syntaxique par rapport au modèle d'héritage prototypique que javavscript incarne. Le mot clé static fonctionne de la manière suivante:

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

}

Dans chrome devtools, nous pouvons bien visualiser ceci:

 static variables javascript

Maintenant, nous avons créé une fonction static que nous pouvons exécuter via ClassName.method() 

0
Willem van der Veen

En travaillant avec les sites Web MVC utilisant jQuery, je souhaite m'assurer que les actions AJAX de certains gestionnaires d'événements ne peuvent être exécutées qu'une fois la requête précédente terminée. J'utilise une variable d'objet "statique" jqXHR pour y parvenir.

Étant donné le bouton suivant:

<button type="button" onclick="ajaxAction(this, { url: '/SomeController/SomeAction' })">Action!</button>

J'utilise généralement un IIFE comme celui-ci pour mon gestionnaire 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);
0
Todd L

J'ai utilisé le prototype et cela a fonctionné:

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

Cat.COLLECTION_NAME = "cats";

ou en utilisant un getter statique:

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

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

Pour les variables statiques privées, j'ai trouvé ceci:

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
0
Martin Wantke

Les vars au niveau de la fenêtre sont en quelque sorte similaires à la statique en ce sens que vous pouvez utiliser une référence directe. Ces références sont disponibles pour toutes les parties de votre application.

0
Bostone

En JavaScript, tout est soit un type primitif, soit un objet . Les fonctions sont des objets - (paires clé-valeur). 

Lorsque vous créez une fonction, vous créez deux objets. Un objet qui représente la fonction elle-même et l'autre qui représente le prototype de la fonction. 

La fonction est fondamentalement dans ce sens un objet avec les propriétés:

function name, 
arguments length 
and the functional prototype.

Donc, où définir la propriété static: Deux emplacements, à l'intérieur de l'objet fonction ou à l'intérieur de l'objet prototype de la fonction. 

Voici un extrait de code qui crée cette fin même en instanciant deux instances, en utilisant le mot clé JavaScript new.

function C () { // function
  var privateProperty = "42";  
  this.publicProperty = "39";  
  
  this.privateMethod = function(){ 
   console.log(privateProperty);
  };
}

C.prototype.publicMethod = function () {    
  console.log(this.publicProperty);
};

C.prototype.staticPrototypeProperty = "4";
C.staticProperty = "3";


var i1 = new C(); // instance 1
var i2 = new C(); // instance 2

i1.privateMethod();
i1.publicMethod();

console.log(i1.__proto__.staticPrototypeProperty);
i1.__proto__.staticPrototypeProperty = "2";
console.log(i2.__proto__.staticPrototypeProperty);

console.log(i1.__proto__.constructor.staticProperty);
i1.__proto__.constructor.staticProperty = "9";
console.log(i2.__proto__.constructor.staticProperty);

L'idée principale est que les instances i1 et i2 utilisent les mêmes propriétés statiques.

0
prosti

Il n’existe pas de variable statique en Javascript. Ce langage est orienté objet et donc il n’existe pas de classes, mais des prototypes à partir desquels les objets se "copient" eux-mêmes.

Vous pouvez les simuler avec des variables globales ou avec un prototypage (en ajoutant une propriété au prototype):

function circle(){
}
circle.prototype.pi=3.14159
0
Gerardo

Je n'ai vu cette idée dans aucune des réponses, alors ajoutez-la simplement à la liste. Si c'est un duplicata, faites le moi savoir et je le supprimerai et je voterai contre l'autre.

J'ai créé une sorte de super global sur mon site web. Comme j'ai plusieurs fichiers js qui sont chargés à chaque chargement de page et des dizaines d'autres fichiers js qui ne sont chargés que sur certaines pages, je mets toutes les fonctions "globales" dans une seule variable globale.

Au sommet de mon premier fichier "global" inclus se trouve la déclaration

var cgf = {}; // Custom global functions.

Puis je délare plusieurs fonctions d’aide globale

cgf.formBehaviors = function()
{
    // My form behaviors that get attached in every page load.
}

Ensuite, si j'ai besoin d'une variable statique, je la stocke simplement en dehors de la portée, par exemple en dehors du document prêt ou en dehors de l'attachement comportemental. (J'utilise jquery mais cela devrait fonctionner 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;
}

Bien sûr, il s’agit d’une approche globale et non statique, mais comme elle est réinitialisée à chaque chargement de page, elle remplit le même objectif.

0
danielson317

J'utilise normalement cette méthode pour 2 raisons principales:

si je veux stocker des valeurs locales de fonctions, j'utilise quelque chose comme "Local.x", "Local.y", "Local.TempData", etc ...!

Si je veux stocker des valeurs statiques de fonctions, j'utilise quelque chose comme "Static.o", "Static.Info", "Static.count", etc ...!

[Update2]: Même méthode, mais utilise l'approche IIFE!

[Update1]: Les objets "statiques" et "locaux" pour les fonctions sont créés automatiquement en pré-édition de scripts!

0
User