web-dev-qa-db-fra.com

Modèle JavaScript pour plusieurs constructeurs

J'ai besoin de constructeurs différents pour mes instances. Quel est un modèle commun pour cela?

90
codeholic

Comment trouvez-vous celui-ci?

function Foobar(foobar) {
    this.foobar = foobar;
}

Foobar.prototype = {
    foobar: null
};

Foobar.fromComponents = function(foo, bar) {
    var foobar = foo + bar;
    return new this(foobar);
};
27
codeholic

JavaScript n'a pas de surcharge de fonctions, y compris pour les méthodes ou les constructeurs.

Si vous souhaitez qu'une fonction se comporte différemment selon le nombre et les types de paramètres que vous lui transmettez, vous devrez les renifler manuellement. JavaScript appellera volontiers une fonction avec plus ou moins que le nombre déclaré d'arguments.

function foo(a, b) {
    if (b===undefined) // parameter was omitted in call
        b= 'some default value';

    if (typeof(a)==='string')
        this._constructInSomeWay(a, b);
    else if (a instanceof MyType)
        this._constructInSomeOtherWay(a, b);
}

Vous pouvez également accéder à arguments sous forme de tableau pour obtenir tous les autres arguments transmis.

Si vous avez besoin d'arguments plus complexes, il peut être judicieux de les mettre en totalité ou en totalité dans une recherche d'objet:

function bar(argmap) {
    if ('optionalparam' in argmap)
        this._constructInSomeWay(argmap.param, argmap.optionalparam);
    ...
}

bar({param: 1, optionalparam: 2})

Python montre comment les arguments par défaut et nommés peuvent être utilisés pour couvrir la plupart des cas d'utilisation de manière plus pratique et plus élégante que la surcharge de fonctions. JavaScript, pas tellement.

106
bobince

Je n'avais pas envie de le faire à la main comme dans la réponse de bobince, alors je viens de complètement arnaquer le modèle d'options du plugin de jQuery.

Voici le constructeur:

//default constructor for Preset 'class'
function Preset(params) {
    var properties = $.extend({
        //these are the defaults
        id: null,
        name: null,
        inItems: [],
        outItems: [],
    }, params);

    console.log('Preset instantiated');
    this.id = properties.id;
    this.name = properties.name;
    this.inItems = properties.inItems;
    this.outItems = properties.outItems;
}

Voici différentes manières d'instanciation:

presetNoParams = new Preset(); 
presetEmptyParams = new Preset({});
presetSomeParams = new Preset({id: 666, inItems:['item_1', 'item_2']});
presetAllParams = new Preset({id: 666, name: 'SOpreset', inItems: ['item_1', 'item_2'], outItems: ['item_3', 'item_4']});

Et voici ce que cela a fait:

presetNoParams
Preset {id: null, name: null, inItems: Array[0], outItems: Array[0]}

presetEmptyParams
Preset {id: null, name: null, inItems: Array[0], outItems: Array[0]}

presetSomeParams
Preset {id: 666, name: null, inItems: Array[2], outItems: Array[0]}

presetAllParams
Preset {id: 666, name: "SOpreset", inItems: Array[2], outItems: Array[2]}
12
Jacob McKay

Pour aller plus loin avec la réponse de eruciform, vous pouvez chaîner votre appel new dans votre méthode init.

function Foo () {
    this.bar = 'baz';
}

Foo.prototype.init_1 = function (bar) {
    this.bar = bar;
    return this;
};

Foo.prototype.init_2 = function (baz) {
    this.bar = 'something to do with '+baz;
    return this;
};

var a = new Foo().init_1('constructor 1');
var b = new Foo().init_2('constructor 2');
9
laughingbovine

Parfois, les valeurs par défaut des paramètres suffisent pour plusieurs constructeurs. Et lorsque cela ne suffit pas, j'essaie de regrouper la plupart des fonctionnalités du constructeur dans une fonction init (other-params) appelée ultérieurement. Pensez également à utiliser le concept d'usine pour créer un objet capable de créer efficacement les autres objets souhaités.

http://en.wikipedia.org/w/index.php?title=Factory_method_pattern&oldid=363482142#Javascript

3
eruciform

Voici l'exemple donné pour plusieurs constructeurs dans programmation en HTML5 avec JavaScript et CSS3 - Réf. Examen .

function Book() {
    //just creates an empty book.
}


function Book(title, length, author) {
    this.title = title;
    this.Length = length;
    this.author = author;
}

Book.prototype = {
    ISBN: "",
    Length: -1,
    genre: "",
    covering: "",
    author: "",
    currentPage: 0,
    title: "",

    flipTo: function FlipToAPage(pNum) {
        this.currentPage = pNum;
    },

    turnPageForward: function turnForward() {
        this.flipTo(this.currentPage++);
    },

    turnPageBackward: function turnBackward() {
        this.flipTo(this.currentPage--);
    }
};

var books = new Array(new Book(), new Book("First Edition", 350, "Random"));
1
Simon Stanford

Donc, oui, comme énoncé précédemment, plusieurs solutions, ce que vous voyez en général dans des choses comme la date sont les méthodes statiques:

Date.UTC("some params"); 

Ce n’est pas un constructeur approprié, c’est bien

function someObject(a,b,c,d,e,f) {
 a = a || "default";
 b = b || "defaultb"
}

Peut aller TypeScript ou le transpiler à es5?

constructor(a:string, b = "default value", c:number? //optional
) {

}
1
Mathijs Segers

vous pouvez utiliser la classe avec des méthodes statiques qui renvoient une instance de cette classe

    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)
        }
        static BAndDInstance(b,d){
            return new MyClass(null,b, null,d)
        }
    }

    //new Instance just with a and other is nul this can
    //use for other params that are first in constructor
    const myclass=new MyClass(a)

    //a Instance that has b and c params
    const BAndC=MyClass.BAndCInstance(b,c)

    //another example for b and d
    const BAndD=MyClass.BAndDInstance(b,d)

avec ce modèle, vous pouvez créer plusieurs constructeurs

0
mahdi shahbazi