Question Quelles techniques peuvent être utilisées pour définir une classe en JavaScript, et quels sont leurs compromis?


Je préfère utiliser OOP dans des projets à grande échelle comme celui sur lequel je travaille en ce moment. J'ai besoin de créer plusieurs classes en JavaScript mais, si je ne me trompe pas, il y a au moins quelques façons de le faire. Quelle serait la syntaxe et pourquoi cela serait-il fait de cette façon?

Je voudrais éviter d'utiliser des bibliothèques tierces - du moins au début.
A la recherche d'autres réponses, j'ai trouvé l'article Programmation orientée objet avec JavaScript, Partie I: Héritage - Doc JavaScript cela discute de la programmation orientée objet en JavaScript. Y a-t-il une meilleure façon de faire l'héritage?


663
2017-12-22 23:07


origine


Réponses:


Voici la façon de le faire sans utiliser de bibliothèques externes:

// Define a class like this
function Person(name, gender){

   // Add object properties like this
   this.name = name;
   this.gender = gender;
}

// Add methods like this.  All Person objects will be able to invoke this
Person.prototype.speak = function(){
    alert("Howdy, my name is" + this.name);
};

// Instantiate new objects with 'new'
var person = new Person("Bob", "M");

// Invoke methods like this
person.speak(); // alerts "Howdy, my name is Bob"

Maintenant, la vraie réponse est beaucoup plus complexe que cela. Par exemple, il n'y a pas de classes en JavaScript. JavaScript utilise un prototypesystème d'héritage basé sur

En outre, il existe de nombreuses bibliothèques JavaScript populaires qui ont leur propre style d'approximation des fonctionnalités de type classe en JavaScript. Vous voulez vérifier au moins Prototype et jQuery.

Décider lequel d'entre eux est le «meilleur» est une excellente façon de commencer une guerre sainte sur Stack Overflow. Si vous vous lancez dans un projet JavaScript plus volumineux, il vaut vraiment la peine d'apprendre une bibliothèque populaire et de le faire à sa manière. Je suis un prototype, mais Stack Overflow semble s'appuyer sur jQuery.

Dans la mesure où il n'y a que «une seule façon de le faire», sans aucune dépendance aux bibliothèques externes, la façon dont j'ai écrit est à peu près tout.


719
2017-12-22 23:16



La meilleure façon de définir une classe en JavaScript est de ne pas définir de classe.

Sérieusement.

Il y a plusieurs goûts différents d'orientation d'objet, certains d'entre eux sont:

  • classe OO (introduit par Smalltalk)
  • prototype basé sur OO (introduit pour la première fois par Self)
  • OO multiméthod-based (d'abord introduit par CommonLoops, je pense)
  • OO à base de prédicats (aucune idée)

Et probablement d'autres que je ne connais pas.

JavaScript implémente OO basé sur un prototype. Dans OO basé sur un prototype, de nouveaux objets sont créés en copiant d'autres objets (au lieu d'être instanciés à partir d'un modèle de classe) et les méthodes vivent directement dans les objets au lieu des classes. L'héritage est fait par délégation: si un objet n'a pas de méthode ou de propriété, il est recherché sur son ou ses prototypes (c'est-à-dire l'objet dont il a été cloné), puis sur les prototypes du prototype et ainsi de suite.

En d'autres termes: il n'y a pas de classes.

JavaScript a en fait un joli tweak de ce modèle: les constructeurs. Non seulement vous pouvez créer des objets en copiant ceux qui existent déjà, mais vous pouvez aussi les construire «hors de l'air», pour ainsi dire. Si vous appelez une fonction avec le new mot-clé, cette fonction devient un constructeur et le this Le mot-clé ne pointera pas vers l'objet actuel mais vers un nouveau "vide". Ainsi, vous pouvez configurer un objet comme vous le souhaitez. De cette manière, les constructeurs JavaScript peuvent assumer l'un des rôles des classes dans les objets OO classiques basés sur les classes: ils servent de modèle ou de modèle pour les nouveaux objets.

Maintenant, JavaScript est un langage très puissant, donc il est assez facile de mettre en œuvre un système OO basé sur les classes dans JavaScript si tu veux. Cependant, vous ne devriez le faire que si vous en avez vraiment besoin et pas seulement parce que c'est ce que fait Java.


210
2017-12-23 16:44



ES2015 Classes

Dans la spécification ES2015, vous pouvez utiliser la syntaxe de classe qui est juste sucre sur le système prototype.

class Person {
  constructor(name) {
    this.name = name;
  }
  toString() {
    return `My name is ${ this.name }.`;
  }
}

class Employee extends Person {
  constructor(name, hours) {
    super(name);
    this.hours = hours;
  }
  toString() {
    return `${ super.toString() } I work ${ this.hours } hours.`;
  }
}

Avantages

Le principal avantage est que les outils d'analyse statique trouvent plus facile de cibler cette syntaxe. Il est également plus facile pour les autres utilisateurs de langues basées sur les classes d'utiliser la langue comme polyglotte.

Avertissements

Méfiez-vous de ses limites actuelles. Pour réaliser des propriétés privées, il faut recourir à en utilisant des symboles ou WeakMaps. Dans les prochaines versions, les classes seront probablement étendues pour inclure ces fonctionnalités manquantes.

Soutien

Support du navigateur n'est pas très bon pour le moment (supporté par presque tout le monde sauf IE), mais vous pouvez utiliser ces fonctionnalités maintenant avec un transpiler comme Babel.

Ressources


74
2018-06-08 04:46



Je préfère utiliser Daniel X. Moore's {SUPER: SYSTEM}. C'est une discipline qui offre des avantages tels que les vraies variables d'instance, l'héritage basé sur les caractères, les hiérarchies de classes et les options de configuration. L'exemple ci-dessous illustre l'utilisation de vraies variables d'instance, ce qui, selon moi, est le plus grand avantage. Si vous n'avez pas besoin de variables d'instance et êtes content avec seulement des variables publiques ou privées, il y a probablement des systèmes plus simples.

function Person(I) {
  I = I || {};

  Object.reverseMerge(I, {
    name: "McLovin",
    age: 25,
    homeState: "Hawaii"
  });

  return {
    introduce: function() {
      return "Hi I'm " + I.name + " and I'm " + I.age;
    }
  };
}

var fogel = Person({
  age: "old enough"
});
fogel.introduce(); // "Hi I'm McLovin and I'm old enough"

Wow, ce n'est pas très utile en soi, mais jetez un œil à l'ajout d'une sous-classe:

function Ninja(I) {
  I = I || {};

  Object.reverseMerge(I, {
    belt: "black"
  });

  // Ninja is a subclass of person
  return Object.extend(Person(I), {
    greetChallenger: function() {
      return "In all my " + I.age + " years as a ninja, I've never met a challenger as worthy as you...";
    }
  });
}

var resig = Ninja({name: "John Resig"});

resig.introduce(); // "Hi I'm John Resig and I'm 25"

Un autre avantage est la possibilité d'avoir des modules et des héritages basés sur les traits.

// The Bindable module
function Bindable() {

  var eventCallbacks = {};

  return {
    bind: function(event, callback) {
      eventCallbacks[event] = eventCallbacks[event] || [];

      eventCallbacks[event].push(callback);
    },

    trigger: function(event) {
      var callbacks = eventCallbacks[event];

      if(callbacks && callbacks.length) {
        var self = this;
        callbacks.forEach(function(callback) {
          callback(self);
        });
      }
    },
  };
}

Un exemple d'avoir la classe personne inclut le module bindable.

function Person(I) {
  I = I || {};

  Object.reverseMerge(I, {
    name: "McLovin",
    age: 25,
    homeState: "Hawaii"
  });

  var self = {
    introduce: function() {
      return "Hi I'm " + I.name + " and I'm " + I.age;
    }
  };

  // Including the Bindable module
  Object.extend(self, Bindable());

  return self;
}

var person = Person();
person.bind("eat", function() {
  alert(person.introduce() + " and I'm eating!");
});

person.trigger("eat"); // Blasts the alert!

Divulgation: Je suis Daniel X. Moore et ceci est mon {SUPER: SYSTEM}. C'est le meilleur moyen de définir une classe en JavaScript.


56
2017-09-16 22:14



var Animal = function(options) {
    var name = options.name;
    var animal = {};

    animal.getName = function() {
        return name;
    };

    var somePrivateMethod = function() {

    };

    return animal;
};

// usage
var cat = Animal({name: 'tiger'});

41
2017-07-23 04:46



Voici les moyens de créer des objets en javascript, que j'ai utilisé jusqu'à présent

Exemple 1:

obj = new Object();
obj.name = 'test';
obj.sayHello = function() {
    console.log('Hello '+ this.name);
}

Exemple 2:

obj = {};
obj.name = 'test';
obj.sayHello = function() {
    console.log('Hello '+ this.name);
}
obj.sayHello();

Exemple 3:

var obj = function(nameParam) {
    this.name = nameParam;
}
obj.prototype.sayHello = function() {
    console.log('Hello '+ this.name);
}

Exemple 4: Avantages réels de Object.create (). veuillez vous référer [ce lien]

var Obj = {
    init: function(nameParam) {
        this.name = nameParam;
    },
    sayHello: function() {
        console.log('Hello '+ this.name);
    }
};
var usrObj = Object.create(Obj);  // <== one level of inheritance

usrObj.init('Bob');
usrObj.sayHello();

Exemple 5 (Crockford's Object.create personnalisé):

Object.build = function(o) {
   var initArgs = Array.prototype.slice.call(arguments,1)
   function F() {
      if((typeof o.init === 'function') && initArgs.length) {
         o.init.apply(this,initArgs)
      }
   }
   F.prototype = o
   return new F()
}
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}  // For example

var userB = {
    init: function(nameParam) {
        this.id = MY_GLOBAL.nextId();
        this.name = nameParam;
    },
    sayHello: function() {
        console.log('Hello '+ this.name);
    }
};
var bob = Object.build(userB, 'Bob');  // Different from your code
bob.sayHello();


Pour conserver la réponse mise à jour avec ES6 / ES2015

Une classe est définie comme ceci:

class Person {
    constructor(strName, numAge) {
        this.name = strName;
        this.age = numAge;
    }

    toString() {
        return '((Class::Person) named ' + this.name + ' & of age ' + this.age + ')';
    }
}

let objPerson = new Person("Bob",33);
console.log(objPerson.toString());

29
2018-03-04 06:49



Je pense que vous devriez lire Douglas Crockford Héritage prototypique en JavaScript et Héritage classique en JavaScript.

Exemples de sa page:

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

Effet? Cela vous permettra d'ajouter des méthodes de manière plus élégante:

function Parenizor(value) {
    this.setValue(value);
}

Parenizor.method('setValue', function (value) {
    this.value = value;
    return this;
});

Je recommande également ses vidéos: JavaScript avancé.

Vous pouvez trouver plus de vidéos sur sa page: http://javascript.crockford.com/ Dans le livre de John Reisig vous pouvez trouver beaucoup d'exemples du site Web de Douglas Crockfor.


24
2017-12-28 22:11