JavaScript: Class.method vs Class.prototype.method

499

Quelle est la différence entre les deux déclarations suivantes?

Class.method = function () { /* code */ }
Class.prototype.method = function () { /* code using this.values */ }

Est-il correct de considérer la première instruction comme une déclaration d'une méthode statique et la seconde comme une déclaration d'une méthode d'instance?

postrationnel
la source

Réponses:

696

Oui, la première fonction n'a aucune relation avec une instance d'objet de cette fonction constructeur , vous pouvez la considérer comme une «méthode statique» .

En JavaScript, les fonctions sont des objets de première classe , ce qui signifie que vous pouvez les traiter comme n'importe quel objet, dans ce cas, vous n'ajoutez qu'une propriété à l' objet fonction .

La deuxième fonction, lorsque vous étendez le prototype de la fonction constructeur, il sera disponible pour toutes les instances d'objet créées avec le newmot - clé, et le contexte dans cette fonction (le thismot - clé) fera référence à l'instance d'objet réelle où vous l'appelez.

Considérez cet exemple:

// constructor function
function MyClass () {
  var privateVariable; // private member only available within the constructor fn

  this.privilegedMethod = function () { // it can access private members
    //..
  };
}

// A 'static method', it's just like a normal function 
// it has no relation with any 'MyClass' object instance
MyClass.staticMethod = function () {};

MyClass.prototype.publicMethod = function () {
  // the 'this' keyword refers to the object instance
  // you can access only 'privileged' and 'public' members
};

var myObj = new MyClass(); // new object instance

myObj.publicMethod();
MyClass.staticMethod();
CMS
la source
1
Mais pourquoi Function.prototype.method == Function.method?
Raghavendra
1
@Raghavendra ce n'est pas
Zorgatone
1
@Menda votre lien est mort
Eugen Sunic
19

Lorsque vous créez plusieurs instances de MyClass, vous n'aurez toujours qu'une seule instance de publicMethod en mémoire, mais en cas de privilegedMethod, vous finirez par créer de nombreuses instances et staticMethod n'a aucune relation avec une instance d'objet.

C'est pourquoi les prototypes économisent de la mémoire.

De plus, si vous modifiez les propriétés de l'objet parent, si la propriété correspondante de l'enfant n'a pas été modifiée, elle sera mise à jour.

user2440156
la source
15

Pour les apprenants visuels, lors de la définition de la fonction sans .prototype

ExampleClass = function(){};
ExampleClass.method = function(customString){
             console.log((customString !== undefined)? 
                          customString : 
                          "called from func def.");}
ExampleClass.method(); // >> output: `called from func def.`  

var someInstance = new ExampleClass();
someInstance.method('Called from instance');
    // >> error! `someInstance.method is not a function`  

Avec le même code, si .prototypeest ajouté,

ExampleClass.prototype.method = function(customString){
             console.log((customString !== undefined)? 
                          customString : 
                          "called from func def.");}
ExampleClass.method();  
      // > error! `ExampleClass.method is not a function.`  

var someInstance = new ExampleClass();
someInstance.method('Called from instance');
                 // > output: `Called from instance`

Pour le rendre plus clair,

ExampleClass = function(){};
ExampleClass.directM = function(){}  //M for method
ExampleClass.prototype.protoM = function(){}

var instanceOfExample = new ExampleClass();

ExampleClass.directM();      works
instanceOfExample.directM();   x Error!

ExampleClass.protoM();     x Error!
instanceOfExample.protoM();   works

**** Remarque pour l'exemple ci-dessus, someInstance.method () ne sera pas exécuté car,
ExampleClass.method () provoque une erreur et l'exécution ne peut pas continuer.
Mais pour des raisons d'illustration et de compréhension, j'ai gardé cette séquence. ****

Résultats générés à partir de chrome developer console& Cliquez sur le lien jsbin ci-dessus pour parcourir le code. Basculer la section commentée avec +JS Bin

ctrl/

SAm
la source
15

Oui, le premier est static methodégalement appelé class method, tandis que le second est un instance method.

Considérez les exemples suivants, pour le comprendre plus en détail.

Dans ES5

function Person(firstName, lastName) {
   this.firstName = firstName;
   this.lastName = lastName;
}

Person.isPerson = function(obj) {
   return obj.constructor === Person;
}

Person.prototype.sayHi = function() {
   return "Hi " + this.firstName;
}

Dans le code ci-dessus, isPersonest une méthode statique, tandis que sayHiest une méthode d'instance de Person.

Ci-dessous, comment créer un objet à partir du Personconstructeur.

var aminu = new Person("Aminu", "Abubakar");

Utilisation de la méthode statique isPerson.

Person.isPerson(aminu); // will return true

Utilisation de la méthode d'instance sayHi.

aminu.sayHi(); // will return "Hi Aminu"

Dans ES6

class Person {
   constructor(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
   }

   static isPerson(obj) {
      return obj.constructor === Person;
   }

   sayHi() {
      return `Hi ${this.firstName}`;
   }
}

Regardez comment le staticmot clé a été utilisé pour déclarer la méthode statique isPerson.

Créer un objet de Personclasse.

const aminu = new Person("Aminu", "Abubakar");

Utilisation de la méthode statique isPerson.

Person.isPerson(aminu); // will return true

Utilisation de la méthode d'instance sayHi.

aminu.sayHi(); // will return "Hi Aminu"

REMARQUE: les deux exemples sont essentiellement les mêmes, JavaScript reste un langage sans classe. Le classintroduit dans ES6 est principalement un sucre syntaxique sur le modèle d'héritage basé sur un prototype existant.

Aminu Kano
la source
"Dans ES6", vous décrivez un sucre de syntaxe uniquement. Ce n'est pas la façon "ES2015" (s'il vous plaît tout le monde arrête d'utiliser ES6 d'utiliser le terme approprié ES2015). C'est simplement une autre façon de procéder et, à mon avis, la mauvaise façon.
K - La toxicité du SO augmente.
2
@KarlMorrison Aminu n'a pas écrit "façon de faire", vous l'avez écrit vous-même et vous y êtes opposé. Votre point peut être juste à propos de ES6 vs ES2015 mais dans la conversation, les gens ont souvent recours à une convention plus courte pour l'efficacité, donc je pense que le supprimer de l'écriture n'est pas possible ou certainement recommandé.
wuliwong
Merci pour la partie ES6 de votre réponse; cela clarifie beaucoup, surtout lorsqu'il est combiné avec les 2 réponses "public + privilégié" ci-dessus. Je suis cependant profondément confus par le obj.constructor === Personfait trueque vous soyez un exemple ... Whaaaat? Comment le constructeur d'une instance de classe peut-il créer ===la classe elle-même ...? (C'est comme dire qu'un sous-ensemble d'un ensemble est l'ensemble lui-même, etc ...)
Andrew
Ohhh ... est-ce que tout cela veut dire que littéralement, le constructeur est tout ce qu'une classe JS est vraiment à la fin de la journée? Tout le reste est soit empilé dans le constructeur, soit totalement une construction statique isolée de la classe, sauf par nom / concept (et comme un "ceci" implicite étant rendu évident)? (Ainsi, ce que je pensais être un sous-ensemble de l'ensemble n'était en fait pas un sous-ensemble.)
Andrew