Je veux écrire ma classe Javascript comme ci-dessous.
class Option {
constructor() {
this.autoLoad = false;
}
constructor(key, value) {
this[key] = value;
}
constructor(key, value, autoLoad) {
this[key] = value;
this.autoLoad = autoLoad || false;
}
}
Je pense que ce serait bien si nous pouvions écrire un cours de cette façon. Attendez-vous à arriver:
var option1 = new Option(); // option1 = {autoLoad: false}
var option2 = new Option('foo', 'bar',); // option2 = {foo: 'bar'}
var option3 = new Option('foo', 'bar', false); // option3 = {foo: 'bar', autoLoad: false}
Je veux écrire ma classe Javascript comme ci-dessous
Vous ne pouvez pas, de la même manière, ne pas surcharger les fonctions standard de ce type. Ce que vous pouvez faites, c'est utiliser l'objet arguments pour interroger le nombre d'arguments transmis:
class Option {
constructor(key, value, autoLoad) {
// new Option()
if(!arguments.length) {
this.autoLoad = false;
}
// new Option(a, [b, [c]])
else {
this[key] = value;
this.autoLoad = autoLoad || false;
}
}
}
Bien sûr (avec votre exemple mis à jour), vous pouvez considérer que le nombre d’arguments ne vous intéresse pas, mais que chaque valeur individuelle est passé, auquel cas vous pourriez avoir quelque chose comme:
class Option {
constructor(key, value, autoLoad) {
if(!key) { // Could change this to a strict undefined check
this.autoLoad = false;
return;
}
this[key] = value;
this.autoLoad = autoLoad || false;
}
}
Ce que vous voulez s'appelle la surcharge du constructeur. Ceci, et le cas plus général de surcharge de fonction , n'est pas pris en charge dans ECMAScript.
ECMAScript ne gère pas les arguments manquants de la même manière que les langages plus stricts. La valeur des arguments manquants est laissée sous la forme undefined
au lieu de générer une erreur. Dans ce paradigme, il est difficile/impossible de détecter la fonction surchargée que vous visez.
La solution idiomatique consiste à avoir une seule fonction et à la faire gérer toutes les combinaisons d'arguments dont vous avez besoin. Pour l'exemple original, vous pouvez simplement tester la présence de key
et value
comme ceci:
class Option {
constructor(key, value, autoLoad = false) {
if (typeof key !== 'undefined') {
this[key] = value;
}
this.autoLoad = autoLoad;
}
}
Une autre option serait d’autoriser votre constructeur à prendre un objet lié à vos propriétés de classe:
class Option {
// Assign default values in the constructor object
constructor({key = 'foo', value, autoLoad = true} = {}) {
this.key = key;
// Or on the property with default (not recommended)
this.value = value || 'bar';
this.autoLoad = autoLoad;
console.log('Result:', this);
}
}
var option1 = new Option();
// Logs: {key: "foo", value: "bar", autoLoad: true}
var option2 = new Option({value: 'hello'});
// Logs: {key: "foo", value: "hello", autoLoad: true}
Ceci est encore plus utile avec TypeScript, car vous pouvez assurer la sécurité du type avec les valeurs transmises (c'est-à-dire que key
ne peut être qu'une chaîne, autoLoad
un booléen, etc.).
Voici un hack pour la surcharge basée sur l'arity (nombre d'arguments). L’idée est de créer une fonction à partir de plusieurs fonctions d’arités différentes (déterminée en regardant fn.length
).
function overloaded(...inputs) {
var fns = [];
inputs.forEach(f => fns[f.length] = f);
return function() {
return fns[arguments.length].apply(this, arguments);
};
}
var F = overloaded(
function(a) { console.log("function with one argument"); },
function(a, b) { console.log("function with two arguments"); }
);
F(1);
F(2, 3);
Bien sûr, cela nécessite beaucoup de protection contre les balles et de nettoyage, mais vous avez l’idée. Cependant, je ne pense pas que vous aurez beaucoup de chance de l’appliquer aux constructeurs de la classe ES6, car c’est un cheval de couleur différente.
D'après votre exemple de code, il vous suffit d'utiliser les valeurs par défaut pour vos paramètres:
class Option {
constructor(key = 'foo', value = 'bar', autoLoad = false) {
this[key] = value;
this.autoLoad = autoLoad;
}
}
Cela dit, une autre alternative à la surcharge de constructeur consiste à utiliser des usines statiques. Supposons que vous souhaitiez pouvoir instancier un objet à partir de paramètres simples, d'un hachage contenant ces mêmes paramètres ou même d'une chaîne JSON:
class Thing {
constructor(a, b) {
this.a = a;
this.b = b;
}
static fromHash(hash) {
return new this(hash.a, hash.b);
}
static fromJson(string) {
return this.fromHash(JSON.parse(string));
}
}
let thing = new Thing(1, 2);
// ...
thing = Thing.fromHash({a: 1, b: 2});
// ...
thing = Thing.fromJson('{"a": 1, "b": 2}');
vous pouvez utiliser des méthodes statiques, regardez ma réponse à la même question
class MyClass {
constructor(a,b,c,d){
this.a = a
this.b = b
this.c = c
this.d = d
}
static BAndCInstance(b,c){
return new MyClass(null,b,c)
}
}
//a Instance that has b and c params
MyClass.BAndCInstance(b,c)