Je construis un composite pour le module request
, mais je ne suis pas sûr de la meilleure pratique concernant la création d'objets dans JS for Node.
Option 1:
function RequestComposite(request) {
return {
get: function (url) { return request.get(url); }
}
}
var comp = RequestComposite(request);
Option 2:
function RequestComposite(request) {
this.request = request;
}
RequestComposite.prototype.get = function (url) { return this.request.get(url); };
var comp = new RequestComposite(request);
Option 3:
var RequestComposite = {
init: function (request) { this.request = request; },
get: function (url) { return request.get(url); }
}
var comp = Object.create(RequestComposite).init(request);
J'essayais de me débrouiller, mais je devenais encore plus confus quant à l'utilisation des objets ...
La réponse serait-elle différente si je veux utiliser des objets pour les navigateurs?
Merci.
Le moyen le plus efficace est le suivant:
Définissez uniquement les propriétés dans le constructeur.
Définissez les méthodes dans la propriété .prototype
du constructeur. Pourquoi? car cela empêche de réécrire chaque méthode chaque fois que vous créez un objet. De cette façon, vous recyclez le même prototype pour chaque objet que vous créez. Efficace en mémoire et dans le temps.
N'utilisez pas de fermetures pour des propriétés privées. Pourquoi ?: Il est lent et vous empêche d'utiliser cet objet dans une chaîne d'héritage (les vars pseudo-privés n'appartiennent pas à l'objet, ils sont simplement accessibles). Utilisez à la place un trait de soulignement pour indiquer qu'il s'agit d'une propriété privée à laquelle vous ne devriez pas accéder de l'extérieur.
Utilisez new
au lieu de Object.create
. C'est plus rapide et à la fin, Object.create utilise new
sous le capot.
En d'autres termes, quelque chose comme ceci:
var Person = function (name) {
this._name = name;
};
Person.prototype.sayHello = function () {
alert('My name is: ' + this._name);
};
var john = new Person('John');
john.sayHello();
Quelques informations supplémentaires:
Object.create vs new. Benchmark ici . Bien que la question concerne node.js, je pense que le même comportement est à prévoir. (toute correction est la bienvenue)
Fermetures pour émuler des propriétés privées: Vous pouvez lire à propos de dans cette question. . Le point où les propriétés privées/de fermeture n'appartiennent pas à l'objet est un fait de programmation: elles sont accessibles par les méthodes d'objet mais n'appartiennent pas à l'objet. Lorsque vous utilisez l'héritage, c'est un gros désastre. De plus, seules les méthodes déclarées dans le constructeur ont accès à la fermeture. Les méthodes définies dans le prototype ne le sont pas.
Définir des méthodes dans le constructeur ou la propriété prototype: lisez cette question , et jetez un coup d'œil à ce point de repère
Les points que j’ai soulevés ici il ya trois ans sont toujours justes du point de vue de la performance, mais mon opinion sur la "méthode recommandée" a légèrement changé entre-temps. Les fonctions d'usine sont en général une bonne option, ce qui constituerait la première approche du PO. Juste un exemple:
function Person(name) {
return {
sayHello: function () { alert('My name is: ' + name); }
};
}
et puis juste faire:
var p = Person('John');
Dans ce cas, vous négociez souplesse (pas de couplage new
, facilité de composition avec d'autres "mix-ins") et de simplicité (pas de désordre this
, instanciation d'objet facile) contre de la vitesse et de la mémoire. En général, ils sont parfaitement valables. Si vous rencontrez des problèmes de performances, et qu’ils sont dus à cette manière de créer des objets, utilisez une autre méthode. L'approche Object.create
est également bonne, tombant en quelque sorte au milieu de new
et des fonctions d'usine (remarque: la nouvelle syntaxe class
est un sucre syntaxique pour new
+ prototype
)
Pour résumer: je recommande de commencer par le moyen le plus simple et le plus simple de créer des objets (fonctions d'usine), puis de recourir à d'autres méthodes lorsque vous rencontrez des problèmes de performances (ce qui dans la plupart des cas n'est jamais).
Il existe de nombreuses façons de créer "Class" et "Object" dans JS. Je préfère cette façon:
var MyObject =
function(args) {
// Private
var help = "/php/index.php?method=getHelp";
var schedule = "/php/index.php?method=getSchedules";
var ajax = function(url, callback, type) {
//....
}
// Public
this.property = 0;
this.getInfo = function() {
// ...
}
// Constructor
function(data) {
this.property = data;
}(args);
};
var o = new MyObject();
Remarque: Si vous êtes plus familier avec la syntaxe OOP, vous pouvez également utiliser class
, qui n'est qu'un sucre syntaxique par rapport à la méthode existante basée sur un prototype.
Performance Comparaison entre 4 façons de créer un objet - avec constructeur (Chrome 61 - https://jsperf.com/create-object-ways )
Option A: Utilisation de return
(La plus rapide 3x)
Option B: Utilisation de {key:value}
(1.5x)
Option C: Utilisation de prototype
(1x) <- Base
Option D: Utilisation de class
(1.02x)
Option A semble fonctionner mieux. Notez que l’augmentation des performances tient en partie au fait qu’elle évite l’utilisation de new
ou object.create
. Donc, juste pour avoir un procès équitable, voici un autre test entre les objets de méthode uniquement, sans constructeur ni propriétés.
Performance Comparaison entre 4 façons de créer un objet contenant uniquement des méthodes (Chrome 61 - https://jsperf.com/create-static-object-ways )
Option A: Utiliser return
(3.2x)
Option B: Utiliser {key:value}
(la plus rapide des 3.3x)
Option C: Utilisation de prototype
(1.8x)
Option D: Utilisation de class
(1.9x)
Option B surperforme un peu Option A. De plus, le goulot d'étranglement causé par object.create
était supérieur à new
.
Meilleur entrainement
Option A (en utilisant return
) est la plus performante dans les deux scénarios. De cette façon, vous pouvez avoir un peu de désordre si vous avez plusieurs méthodes et propriétés.
Je préfère diviser le constructeur et les propriétés en un objet séparé à l'aide de Option A et des méthodes dans un autre objet à l'aide de Option B. Cette approche nécessite l'envoi d'une référence instance
supplémentaire dans les paramètres, mais elle peut être utile si vous avez plusieurs objets utilisant les mêmes propriétés et constructeurs (il est également possible d'obtenir un héritage OOP).
Exemple:
// Constructor & Properties Object (Using option A)
var UserData = function(request){
// Constructor
if ( request.name )
var name = request.name;
else
var name = 'Not Available';
if ( request.age )
var age = request.age;
else
var age = null;
// Return properties
return {
userName: name,
userAge: age
};
};
// Object methods (Using Option B)
var Adults = {
printName: function(instance){ // Read propery example
console.log( 'Mr. ' + instance.userName );
},
changeName: function(instance, newName){ // Write property example
instance.userName = newName;
},
foo: function(){
console.log( 'foo' );
}
};
// Object methods (Using Option B)
var Children = {
printName: function(instance){
console.log( 'Master ' + instance.userName );
},
bar: function(){
console.log( 'bar' );
}
}
// Initialize
var userData = UserData ( {name: 'Doe', age: 40} );
// Call methods
Adults.printName(userData); // Output 'Mr. Doe'
Children.printName(userData); // Output 'Master Doe'
Adults.foo(); // Output 'foo'
Children.bar(); // Output 'bar'
Adults.changeName(userData, 'John');
Adults.printName(userData); // Output 'Mr. John'