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



Answers

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 se 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, etc.

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 mot this clé this 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 d'implémenter un système OO basé sur les classes dans JavaScript si vous le souhaitez. Cependant, vous ne devriez le faire que si vous en avez vraiment besoin et pas seulement parce que c'est ce que fait Java.

Question

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.
À la recherche d'autres réponses, j'ai trouvé l'article Programmation orientée objet avec JavaScript, Partie I: Inheritance - Doc JavaScript qui traite de la programmation orientée objet en JavaScript. Y a-t-il une meilleure façon de faire l'héritage?




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



JavaScript est object-oriented , mais il est radicalement différent des autres OOP comme Java, C # ou C ++. N'essayez pas de le comprendre comme ça. Jetez cette vieille connaissance et recommencez à zéro. JavaScript a besoin d'une réflexion différente.

Je suggère d'obtenir un bon manuel ou quelque chose sur le sujet. J'ai moi-même trouvé les tutoriels ExtJS les meilleurs pour moi, même si je n'ai pas utilisé le framework avant ou après l'avoir lu. Mais cela donne une bonne explication sur ce qui est quoi dans le monde JavaScript. Désolé, il semble que ce contenu a été supprimé. Voici un lien vers archive.org à la place. Fonctionne aujourd'hui. : P




Parce que je ne vais pas admettre le plan d'usine YUI / Crockford et parce que j'aime garder les choses autonomes et extensibles c'est ma variante:

function Person(params)
{
  this.name = params.name || defaultnamevalue;
  this.role = params.role || defaultrolevalue;

  if(typeof(this.speak)=='undefined') //guarantees one time prototyping
  {
    Person.prototype.speak = function() {/* do whatever */};
  }
}

var Robert = new Person({name:'Bob'});

où idéalement le test typeof est sur quelque chose comme la première méthode prototypée




Je préfère utiliser {SUPER: SYSTEM} Daniel X. Moore. 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 {SUPER: SYSTEM} mon {SUPER: SYSTEM} . C'est le meilleur moyen de définir une classe en JavaScript.




var Student = (function () {
    function Student(firstname, lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
        this.fullname = firstname + " " + lastname;
    }

    Student.prototype.sayMyName = function () {
        return this.fullname;
    };

    return Student;
}());

var user = new Student("Jane", "User");
var user_fullname = user.sayMyName();

C'est comme ça que TypeScript compile la classe avec le constructeur en JavaScript.




MooTools (My Object Oriented Tools) est centré sur l'idée des classes . Vous pouvez même étendre et implémenter avec l'héritage.

Une fois maîtrisé, il rend ridiculement réutilisable, javascript puissant.




Le moyen simple est:

function Foo(a) {
  var that=this;

  function privateMethod() { .. }

  // public methods
  that.add = function(b) {
    return a + b;
  };
  that.avg = function(b) {
    return that.add(b) / 2; // calling another public method
  };
}

var x = new Foo(10);
alert(x.add(2)); // 12
alert(x.avg(20)); // 15

La raison en est que this peut être lié à autre chose si vous donnez une méthode en tant que gestionnaire d'événement, donc vous enregistrez la valeur pendant l'instanciation et l'utilisez plus tard.

Edit: ce n'est certainement pas le meilleur moyen, juste un moyen simple. J'attends de bonnes réponses aussi!




Une base

function Base(kind) {
    this.kind = kind;
}

Une classe

// Shared var
var _greeting;

(function _init() {
    Class.prototype = new Base();
    Class.prototype.constructor = Class;
    Class.prototype.log = function() { _log.apply(this, arguments); }
    _greeting = "Good afternoon!";
})();

function Class(name, kind) {
    Base.call(this, kind);
    this.name = name;
}

// Shared function
function _log() {
    console.log(_greeting + " Me name is " + this.name + " and I'm a " + this.kind);
}

action

var c = new Class("Joe", "Object");
c.log(); // "Good afternoon! Me name is Joe and I'm a Object"



Links