• JAVASCRIPT > les classes

      static

      class Triple {
        static triple(n) {
          if (n === undefined) {
            n = 1;
          }
          return n * 3;
        }
      }
      
      class SuperTriple extends Triple {
        static triple(n) {
          return super.triple(n) * super.triple(n);
        }
      }
      
      console.log(Triple.triple());       // 3
      console.log(Triple.triple(6));      // 18
      console.log(SuperTriple.triple(4)); // 144
      var tp = new Triple();
      console.log(SuperTriple.triple(4)); // 144 (pas d'impact de l'affectation du parent)
      console.log(tp.triple()); // tp.triple n'est pas une fonction

      Utilisation depuis une autre méthode statique

      Afin d’appeler une autre méthode statique dans une méthode statique, on pourra utiliser this.

      class StaticMethodCall {
        static staticMethod() {
          return 'Méthode statique appelée';
        }
        static anotherStaticMethod() {
          return this.staticMethod() + ' depuis une autre statique';
        }
      }
      StaticMethodCall.staticMethod();
      // 'Méthode statique appelée'
      StaticMethodCall.anotherStaticMethod();
      // 'Méthode statique appelée depuis une autre statique'

      Depuis les constructeurs de classes et les autres méthodes

      Les méthodes statiques ne sont pas directement accessibles via le mot-clé this. Il faut les appeler avec le nom de la classe qui préfixe le nom de la méthode statique NomDeClasse.MéthodeStatique() (comme pour les autres appels en dehors de la classe) ou avec la propriété constructor : this.constructor.MéthodeStatique().

      class StaticMethodCall{
        constructor(){
          console.log(StaticMethodCall.staticMethod());
          // 'appel de la méthode statique'
      
          console.log(this.constructor.staticMethod());
          // 'appel de la méthode statique'
        }
      
        static  staticMethod(){
          return 'appel de la méthode statique.';
        }
      }

      Static

      class User {
        static staticMethod() {
          alert(this === User);
        }
      }
      User.staticMethod();

       

      class Article {
        constructor(title, date) {
          this.title = title;
          this.date = date;
        }
      
        static compare(articleA, articleB) {
          return articleA.date - articleB.date;
        }
      }
      
      let articles = [
        new Article("HTML", new Date(2019, 1, 1)),
        new Article("CSS", new Date(2019, 0, 1)),
        new Article("JavaScript", new Date(2019, 11, 1))
      ];
      
      articles.sort(Article.compare);

       

      class Article {
        constructor(title, date) {
          this.title = title;
          this.date = date;
        }
      
        static createTodays() {
          // remember, this = Article
          return new this("Today's digest", new Date());
        }
      }
      
      let article = Article.createTodays();
      alert( article.title ); // Today's digest

      Now every time we need to create a today’s digest, we can call Article.createTodays(). Once again, that’s not a method of an article, but a method of the whole class.

      Static methods are also used in database-related classes to search/save/remove entries from the database, like this:

      // assuming Article is a special class for managing articles
      // static method to remove the article:
      Article.remove({id: 12345});

      Static properties

      class Article {
        static publisher = "Ilya Kantor";
      }

      Inheritance of static properties and methods

      class Animal {
        static planet = "Earth";
      
        constructor(name, speed) {
          this.speed = speed;
          this.name = name;
        }
      
        run(speed = 0) {
          this.speed += speed;
          alert(`${this.name} runs with speed ${this.speed}.`);
        }
      
        static compare(animalA, animalB) {
          return animalA.speed - animalB.speed;
        }
      }
      
      // Inherit from Animal
      class Rabbit extends Animal {
        hide() {
          alert(`${this.name} hides!`);
        }
      }
      
      let rabbits = [
        new Rabbit("White Rabbit", 10),
        new Rabbit("Black Rabbit", 5)
      ];
      
      rabbits.sort(Rabbit.compare);
      
      rabbits[0].run(); // Black Rabbit runs with speed 5.
      
      alert(Rabbit.planet); // Earth

      Now when we call Rabbit.compare, the inherited Animal.compare will be called.

      How does it work? Again, using prototypes. As you might have already guessed, extends gives Rabbit the [[Prototype]] reference to Animal.

      So, Rabbit extends Animal creates two [[Prototype]] references:

      1. Rabbit function prototypally inherits from Animal function.
      2. Rabbit.prototype prototypally inherits from Animal.prototype.

      As a result, inheritance works both for regular and static methods.

      Here, let’s check that by code:

      class Animal {}
      class Rabbit extends Animal {}
      
      // for statics
      alert(Rabbit.__proto__ === Animal); // true
      
      // for regular methods
      alert(Rabbit.prototype.__proto__ === Animal.prototype); // true

      Summary

      Static methods are used for the functionality that belongs to the class “as a whole”. It doesn’t relate to a concrete class instance.

      For example, a method for comparison Article.compare(article1, article2) or a factory method Article.createTodays().

      They are labeled by the word static in class declaration.

      Static properties are used when we’d like to store class-level data, also not bound to an instance.

      The syntax is:

      class MyClass {
        static property = ...;
      
        static method() {
          ...
        }
      }

      Technically, static declaration is the same as assigning to the class itself:

      MyClass.property = ...
      MyClass.method = ...

      Static properties and methods are inherited.

      For class B extends A the prototype of the class B itself points to A: B.[[Prototype]] = A. So if a field is not found in B, the search continues in A.

      Tasks

      Class extends Object?

      importance: 3

      As we know, all objects normally inherit from Object.prototype and get access to “generic” object methods like hasOwnProperty etc.

      For instance:

      class Rabbit {
        constructor(name) {
          this.name = name;
        }
      }
      
      let rabbit = new Rabbit("Rab");
      // hasOwnProperty method is from Object.prototype
      alert( rabbit.hasOwnProperty('name') ); // true

      But if we spell it out explicitly like "class Rabbit extends Object", then the result would be different from a simple "class Rabbit"?

      What’s the difference?

      Here’s an example of such code (it doesn’t work – why? fix it?):

      class Rabbit extends Object {
        constructor(name) {
          this.name = name;
        }
      }
      
      let rabbit = new Rabbit("Rab");
      alert( rabbit.hasOwnProperty('name') ); // Error

      First, let’s see why the latter code doesn’t work.

      The reason becomes obvious if we try to run it. An inheriting class constructor must call super(). Otherwise "this" won’t be “defined”.

      So here’s the fix:

      class Rabbit extends Object {
        constructor(name) {
          super(); // need to call the parent constructor when inheriting
          this.name = name;
        }
      }
      
      let rabbit = new Rabbit("Rab");
      alert( rabbit.hasOwnProperty('name') ); // true

      But that’s not all yet.

      Even after the fix, there’s still important difference in "class Rabbit extends Object" versus class Rabbit.

      As we know, the “extends” syntax sets up two prototypes:

      1. Between "prototype" of the constructor functions (for methods).
      2. Between the constructor functions themselves (for static methods).

      In our case, for class Rabbit extends Object it means:

      class Rabbit extends Object {}

      So Rabbit now provides access to static methods of Object via Rabbit, like this:

      class Rabbit extends Object {}
      
      // normally we call Object.getOwnPropertyNames
      alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b

       

      So Rabbit doesn’t provide access to static methods of Object in that case.

       

 

Aucun commentaire

 

Laissez un commentaire