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 deux façons de le faire. Quelle serait la syntaxe et pourquoi le ferait-on de cette façon?

je voudrais éviter d'utiliser des bibliothèques tierces, du moins au premier abord.

À 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. Est-il une meilleure façon de faire de l'héritage?

668
demandé sur Daniel X Moore 2008-12-23 02:07:04
la source

19 ответов

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'existe pas de classes dans JavaScript. JavaScript utilise un schéma d'héritage basé sur prototype .

en outre, il existe de nombreuses bibliothèques JavaScript populaires qui ont leur propre style d'approximation de la fonctionnalité de classe en JavaScript. Vous voudrez vérifier à Prototype et jQuery .

Décider quel est le "meilleur" est une excellente façon de commencer une guerre sainte, sur un Débordement de Pile. Si vous vous lancez dans un plus grand projet JavaScript-lourd, il est certainement la peine d'apprendre une bibliothèque populaire et de le faire à leur façon. Je suis un Prototype, mais Stack Overflow semble pencher vers jQuery.

pour autant qu'il n'y ait qu'une seule façon de le faire, sans aucune les dépendances sur les bibliothèques externes, la façon dont j'ai écrit est à peu près il.

724
répondu Triptych 2017-08-01 17:06:53
la source

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

sérieusement.

il y a plusieurs saveurs différentes d'orientation-objet, certains d'entre eux sont:

  • de classe OO (d'abord été introduit par Smalltalk)
  • basé sur des prototypes OO (introduit d'abord par Soi-même)
  • multimethod à base OO (d'abord été introduit par CommonLoops, je pense)
  • prédicat de base OO (aucune idée)

Et probablement d'autres que je ne connais pas.

JavaScript met en œuvre un prototype à base de OO. Dans OO basé sur 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 de dans les 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 prototype(s) (c'est-à-dire l'objet à partir duquel il a été cloné), puis les prototypes du prototype et ainsi de suite.

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

JavaScript a en fait un bon 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 mot-clé new , cette fonction devient un constructeur et le mot-clé this ne pointera pas vers l'objet courant mais à la place à un "vide" nouvellement créé. Ainsi, vous pouvez configurer un objet comme vous le souhaitez. De cette façon, les constructeurs JavaScript peuvent assumer l'un des rôles des classes dans l'OO traditionnel basé sur la classe: servir de modèle ou de modèle pour les nouveaux objets.

maintenant, JavaScript est un langage très puissant, il est donc assez facile de mettre en œuvre un système oo basé sur la classe dans JavaScript si vous voulez. Cependant, vous devez seulement faire ceci si vous avez vraiment besoin et pas seulement parce que c'est la façon dont Java t-il.

210
répondu Jörg W Mittag 2008-12-23 19:44:21
la source

ES2015 Classes

dans la spécification ES2015, vous pouvez utiliser la syntaxe de classe qui est juste du 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.`;
  }
}

prestations

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

mises en garde

méfiez-vous ses limites actuelles. Pour obtenir des propriétés privées, on doit recourir à en utilisant des symboles ou des points faibles . Dans les versions futures, les classes seront probablement élargies pour inclure ces fonctionnalités manquantes.

Support

prise en charge du Navigateur n'est pas très bon à l'instant (pris en charge par presque tout le monde sauf IE), mais vous pouvez utiliser ces fonctionnalités avec un transpiler comme Babel .

ressources

74
répondu Dale 2017-08-01 18:27:13
la source

je préfère utiliser celui de Daniel X. Moore {SUPER: SYSTEM} . C'est une discipline qui fournit des avantages tels que les variables d'instance vraies, l'héritage basé sur les traits, les hiérarchies de classe et les options de configuration. L'exemple ci-dessous illustre l'utilisation de vraies variables d'instance, ce qui est à mon avis le plus grand avantage. Si vous n'avez pas besoin de variables d'instance et que vous n'êtes satisfait que des variables publiques ou privées, alors 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 vraiment très utile en soi, mais regardez 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 un héritage basé 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 de classe de personnes comprenant le module à relier.

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 c'est mon {SUPER: SYSTEM} . C'est la meilleure façon de définissez une classe en JavaScript.

56
répondu Daniel X Moore 2010-09-17 02:14:51
la source
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
répondu liammclennan 2009-07-23 08:46:05
la source

ce qui suit sont les façons 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 L'objet.créer.)( 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 (objet personnalisé de Crockford.create):

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 garder la réponse à jour avec ES6 / ES2015

une classe est définie comme suit:

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
répondu Amol M Kulkarni 2018-01-03 12:12:52
la source

je pense que vous devriez lire héritage prototypique de Douglas Crockford 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? Il vous permettra d'ajouter des méthodes de façon plus élégante:

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

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

je recommande aussi ses vidéos: "1519130920 Avancée" JavaScript .

vous pouvez voir plus de vidéos sur sa page: http://javascript.crockford.com / Dans le Livre de John Reisig, vous pouvez trouver de nombreux exemples sur le site Web de Douglas Crockfor.

24
répondu Jarek 2008-12-23 20:51:29
la source

parce que je n'admettrai pas le plan d'usine de 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 type de test est sur quelque chose comme la première méthode prototypé

16
répondu annakata 2008-12-29 01:11:29
la source

si vous optez pour simple, vous pouvez éviter le" nouveau " mot-clé entièrement et juste utiliser des méthodes d'usine. Je préfère ça, parfois, parce que j'aime utiliser JSON pour créer des objets.

function getSomeObj(var1, var2){
  var obj = {
     instancevar1: var1,
     instancevar2: var2,
     someMethod: function(param)
     {  
          //stuff; 
     }
  };
  return obj;
}

var myobj = getSomeObj("var1", "var2");
myobj.someMethod("bla");

Je ne suis pas sûr de ce que le succès de performance est pour les grands objets, cependant.

15
répondu Sam 2013-05-28 11:12:25
la source
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 la façon dont TypeScript compile class with constructor to JavaScript.

12
répondu Mick 2016-09-02 23:58:33
la source

la voie 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 pour that est que this peut être lié à autre chose si vous donnez une méthode comme gestionnaire d'événements, donc vous sauvegardez la valeur pendant l'instanciation et l'utilisez plus tard.

Edit: ce n'est certainement pas la meilleure façon, juste une façon simple. Je suis en attente de réponses de bon aussi!

10
répondu orip 2008-12-23 02:33:03
la source

vous voulez probablement créer un type en utilisant le motif de pliage:

    // Here is the constructor section.
    var myType = function () {
        var N = {}, // Enclosed (private) members are here.
            X = this; // Exposed (public) members are here.

        (function ENCLOSED_FIELDS() {
            N.toggle = false;
            N.text = '';
        }());

        (function EXPOSED_FIELDS() {
            X.count = 0;
            X.numbers = [1, 2, 3];
        }());

        // The properties below have access to the enclosed fields.
        // Careful with functions exposed within the closure of the
        // constructor, each new instance will have it's own copy.
        (function EXPOSED_PROPERTIES_WITHIN_CONSTRUCTOR() {
            Object.defineProperty(X, 'toggle', {
                get: function () {
                    var before = N.toggle;
                    N.toggle = !N.toggle;
                    return before;
                }
            });

            Object.defineProperty(X, 'text', {
                get: function () {
                    return N.text;
                },
                set: function (value) {
                    N.text = value;
                }
            });
        }());
    };

    // Here is the prototype section.
    (function PROTOTYPE() {
        var P = myType.prototype;

        (function EXPOSED_PROPERTIES_WITHIN_PROTOTYPE() {
            Object.defineProperty(P, 'numberLength', {
                get: function () {
                    return this.numbers.length;
                }
            });
        }());

        (function EXPOSED_METHODS() {
            P.incrementNumbersByCount = function () {
                var i;
                for (i = 0; i < this.numbers.length; i++) {
                    this.numbers[i] += this.count;
                }
            };
            P.tweak = function () {
                if (this.toggle) {
                    this.count++;
                }
                this.text = 'tweaked';
            };
        }());
    }());

ce code vous donnera un type appelé myType . Il aura des champs privés internes appelés bascule et texte . Il aura également ces membres exposés: les champs count et nombres ; les propriétés toggle , texte et numberLength ; les méthodes incrementNumbersByCount et tweak .

le schéma de pliage est détaillé ici: Motif De Pliage Javascript

9
répondu intrepidis 2013-04-07 04:43:50
la source

code golf pour réponse de @liammclennan .

var Animal = function (args) {
  return {
    name: args.name,

    getName: function () {
      return this.name; // member access
    },

    callGetName: function () {
      return this.getName(); // method call
    }
  };
};

var cat = Animal({ name: 'tiger' });
console.log(cat.callGetName());
3
répondu tponthieux 2017-05-23 15:18:27
la source

MooTools (mes outils orientés objet) est centré sur l'idée de classes . Vous pouvez même étendre et mettre en œuvre avec l'héritage.

lorsqu'il est maîtrisé, il rend le javascript ridiculement réutilisable et puissant.

2
répondu Ryan Florence 2009-05-30 06:22:36
la source

classes basées sur L'objet avec héritage

var baseObject = 
{
     // Replication / Constructor function
     new : function(){
         return Object.create(this);   
     },

    aProperty : null,
    aMethod : function(param){
      alert("Heres your " + param + "!");
    },
}


newObject = baseObject.new();
newObject.aProperty = "Hello";

anotherObject = Object.create(baseObject); 
anotherObject.aProperty = "There";

console.log(newObject.aProperty) // "Hello"
console.log(anotherObject.aProperty) // "There"
console.log(baseObject.aProperty) // null

Simple, doux,et se fait.

2
répondu Ulad Kasach 2016-04-05 18:23:45
la source

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"
1
répondu Mikael Dúi Bolinder 2017-07-18 14:28:01
la source

basé sur L'exemple de Triptyque, cela pourrait même être plus simple:

    // Define a class and instantiate it
    var ThePerson = new function Person(name, gender) {
        // Add class data members
        this.name = name;
        this.gender = gender;
        // Add class methods
        this.hello = function () { alert('Hello, this is ' + this.name); }
    }("Bob", "M"); // this instantiates the 'new' object

    // Use the object
    ThePerson.hello(); // alerts "Hello, this is Bob"

cela ne crée qu'une instance d'objet unique, mais est toujours utile si vous voulez encapsuler un tas de noms pour la variable et les méthodes dans une classe. Normalement il n'y aurait pas les arguments" Bob, M " au constructeur, par exemple si les méthodes seraient des appels à un système avec ses propres données, comme une base de données ou un réseau.

je suis encore trop nouveau avec JS pour voir pourquoi ceci n'utilise pas la chose prototype .

1
répondu Roland 2017-08-23 11:39:38
la source

JavaScript est orienté objet , mais il est radicalement différent que d'autres OOP les langues comme Java, C# ou C++. N'essaie pas de comprendre ça comme ça. Jeter cette vieille connaissance de sortir et de commencer à nouveau. JavaScript a besoin d'une pensée différente.

je suggère d'avoir un bon manuel ou quelque chose sur le sujet. je me suis trouvé ExtJS Tutoriels le mieux pour moi, même si je n'ai pas utilisé le cadre avant ou après la lecture. Mais il donne une bonne explication sur ce qui est dans le monde JavaScript. Désolé, il semble que ce contenu a été supprimé. Voici le lien vers archive.org copiez à la place. Travaille aujourd'hui. : P

0
répondu Vilx- 2013-08-03 10:26:54
la source

//new way using this and new
function Persons(name) {
  this.name = name;
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name + '.');
  };
}

var gee=new Persons("gee");
gee.greeting();

var gray=new Persons("gray");
gray.greeting();

//old way
function createPerson(name){
 var obj={};
 obj.name=name;
 obj.greeting = function(){
 console.log("hello I am"+obj.name);
 }; 
  return obj;
}

var gita=createPerson('Gita');
gita.greeting();
0
répondu Avinash Maurya 2018-09-13 06:03:51
la source

Autres questions sur javascript class oop