272 votes

Classe et méthode statique en JavaScript

Je sais que ça va marcher :

function Foo() {};
Foo.prototype.talk = function () {
    alert('hello~\n');
};

var a = new Foo;
a.talk(); // 'hello~\n'

Mais si je veux appeler

Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly

Je trouve des méthodes pour faire Foo.talk travail,

  1. Foo.__proto__ = Foo.prototype
  2. Foo.talk = Foo.prototype.talk

Y a-t-il d'autres façons de procéder ? Je ne sais pas si c'est bien de le faire. Utilisez-vous des méthodes de classe ou des méthodes statiques dans votre code JavaScript ?

14 votes

Foo.talk = function ...

1 votes

@downvoterstepintothelight Le Foo.walk = function() {} n'aura pas d'effet sur ses instances, puisqu'il ne se trouve pas dans la chaîne des prototypes. Existe-t-il une méthode inter-navigateur permettant de rendre la fonction [[prototype]] point à son prototype ?

3 votes

Probablement que je n'ai aucune idée de ce que tu veux, parce que les méthodes de la classe n'affectent pas les instances par définition.

428voto

zzzzBov Points 62084

Tout d'abord, rappelez-vous que JavaScript est principalement un langage prototypique plutôt qu'un langue de classe 1 . Foo n'est pas une classe, c'est une fonction, qui est un objet. Vous pouvez instancier un objet de cette fonction en utilisant le new qui vous permettra de créer quelque chose de similaire à une classe dans un langage OOP standard.

Je suggère d'ignorer __proto__ la plupart du temps parce qu'il est mal supporté par les différents navigateurs. prototype travaux.

Si vous avez une instance d'un objet créé à partir d'une fonction 2 et que vous accédez à l'un de ses membres (méthodes, attributs, propriétés, constantes, etc.) de quelque manière que ce soit, l'accès s'effectuera dans la hiérarchie des prototypes jusqu'à ce qu'il (a) trouve le membre, ou (b) ne trouve pas d'autre prototype.

La hiérarchie commence sur l'objet qui a été appelé, puis recherche son objet prototype. Si l'objet prototype a un prototype, elle répète, si aucun prototype n'existe, undefined est renvoyé.

Par exemple :

foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"

foo = {};
console.log(foo.bar); // logs undefined

function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set

Il me semble que vous avez déjà compris au moins en partie ces parties "de base", mais je dois les rendre explicites, juste pour être sûr.

En JavaScript, tout est un objet 3 .

tout est un objet.

function Foo(){} ne se contente pas de définir une nouvelle fonction, elle définit un nouvel objet fonction auquel on peut accéder à l'aide de la fonction Foo .

C'est pourquoi vous pouvez accéder Foo avec le prototype de Foo.prototype .

Ce que vous pouvez également faire est de définir plus de fonctions sur Foo :

Foo.talk = function () {
  alert('hello world!');
};

Cette nouvelle fonction est accessible en utilisant :

Foo.talk();

J'espère que vous remarquez maintenant une similitude entre les fonctions sur un objet fonction et une méthode statique.

Pensez à f = new Foo(); comme la création d'une instance de classe, Foo.prototype.bar = function(){...} comme la définition d'une méthode partagée pour la classe, et Foo.baz = function(){...} comme la définition d'une méthode statique publique pour la classe.


ECMAScript 2015 a introduit une variété de sucre syntaxique pour ces types de déclarations afin de les rendre plus simples à mettre en œuvre tout en étant plus faciles à lire. L'exemple précédent peut donc être écrit comme suit :

class Foo {
  bar() {...}

  static baz() {...}
}

qui permet bar pour être appelé comme :

const f = new Foo()
f.bar()

et baz pour être appelé comme :

Foo.baz()

1 : <a href="http://es5.github.io/#x7.6.1.2" rel="noreferrer"><code>class</code> était un "futur mot réservé" dans la spécification ECMAScript 5. </a>mais ES6 introduit la possibilité de définir des classes à l'aide de l'attribut <code>class</code> mot-clé.

2 : essentiellement une instance de classe créée par un constructeur, mais il existe de nombreuses différences nuancées que je ne veux pas vous induire en erreur.

3 : <a href="http://es5.github.io/#x4.3.2" rel="noreferrer">valeurs primitives </a>-qui comprennent <code>undefined</code> , <code>null</code> Les booléens, les nombres et les chaînes de caractères ne sont pas techniquement des objets car ils sont des implémentations de langage de bas niveau. Les booléens, les nombres et les chaînes de caractères interagissent toujours avec la chaîne de prototypes comme s'ils étaient des objets, donc pour les besoins de cette réponse, il est plus facile de les considérer comme des "objets" même s'ils ne le sont pas tout à fait.

0 votes

Eh bien, je veux juste que ce soit un peu comme les langues d'oop. Dois-je utiliser Foo.talk = Foo.prototype.talk afin d'éviter la définition en double de talk ?

0 votes

@lostyzd - pourquoi est-ce une méthode pour commencer ? Soit elle utilise this et doit être appelée en tant que méthode d'instance, ou bien elle n'utilise pas la fonction this et vous pouvez en faire un simple attribut de Foo (et que les instances appellent Foo.talk() ).

0 votes

@nrabinowitz J'essaie de faire en sorte que les instances aient accès à la méthode de leur constructeur (méthode statique).

69voto

Bipul Kumar Points 178

Vous pouvez le réaliser comme suit :

function Foo() {};

Foo.talk = function() { alert('I am talking.'); };

Vous pouvez maintenant invoquer la fonction "talk" comme ci-dessous :

Foo.talk();

Vous pouvez le faire parce qu'en JavaScript, les fonctions sont également des objets.

40voto

Eduardo Cuomo Points 1433

Appeler une méthode statique à partir d'une instance :

function Clazz() {};
Clazz.staticMethod = function() {
    alert('STATIC!!!');
};

Clazz.prototype.func = function() {
    this.constructor.staticMethod();
}

var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"

Projet de classe Javascript simple : https://github.com/reduardo7/sjsClass

14 votes

Il ne s'agit pas d'un appel statique. var obj = new Clazz() ; crée un nouveau instance de Clazz. Cependant, Clazz.staticMethod() permet d'obtenir le résultat sans tous ces autres éléments.

5 votes

@mpemburn : Eduardo est également correct dans sa réponse. Ce qu'il vous montre, c'est que non seulement vous pouvez appeler la méthode statique de "l'extérieur" par l'intermédiaire de Clazz.staticMethod mais il vous montre comment faire un lien vers ces méthodes statiques à partir d'un objet instancié. Ceci est particulièrement utile dans des environnements comme Node.js où, en utilisant require, vous n'avez pas forcément un accès direct au constructeur original. La seule chose que je voudrais ajouter est this.constructor.staticMethod.apply(this, arguments);

1 votes

Absolument génial, fonctionne même à l'intérieur d'un constructeur de café-script : constructor: (a) -> @constructor.add @ (enfin presque, en tout cas)

34voto

Jaskey Points 368

Voici un bon exemple pour démontrer comment Javascript fonctionne avec les variables et méthodes statiques/instance.

function Animal(name) {
    Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
    this.name = name; //instance variable, using "this"
}

Animal.showCount = function () {//static method
    alert(Animal.count)
}

Animal.prototype.showName=function(){//instance method
    alert(this.name);
}

var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");

Animal.showCount();  // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from  Java

33voto

Dima Fomin Points 688

En complément, il est maintenant possible de faire avec class y static

'use strict'

class Foo {
 static talk() {
     console.log('talk')
 };

 speak() {
     console.log('speak')
 };

};

donnera

var a = new Foo();
Foo.talk();  // 'talk'
a.talk();    // err 'is not a function'
a.speak();   // 'speak'
Foo.speak(); // err 'is not a function'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X