JavaScript pattern for multiple constructors

前端 未结 9 949
不知归路
不知归路 2020-12-07 13:12

I need different constructors for my instances. What is a common pattern for that?

相关标签:
9条回答
  • 2020-12-07 13:21

    How do you find this one?

    function Foobar(foobar) {
        this.foobar = foobar;
    }
    
    Foobar.prototype = {
        foobar: null
    };
    
    Foobar.fromComponents = function(foo, bar) {
        var foobar = foo + bar;
        return new Foobar(foobar);
    };
    
    //usage: the following two lines give the same result
    var x = Foobar.fromComponents('Abc', 'Cde');
    var y = new Foobar('AbcDef')
    
    0 讨论(0)
  • 2020-12-07 13:24

    Didn't feel like doing it by hand as in bobince's answer, so I just completely ripped off jQuery's plugin options pattern.

    Here's the constructor:

    //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;
    }
    

    Here's different ways of instantiation:

    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']});
    

    And here's what that made:

    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]}
    
    0 讨论(0)
  • 2020-12-07 13:27

    JavaScript doesn't have function overloading, including for methods or constructors.

    If you want a function to behave differently depending on the number and types of parameters you pass to it, you'll have to sniff them manually. JavaScript will happily call a function with more or fewer than the declared number of 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);
    }
    

    You can also access arguments as an array-like to get any further arguments passed in.

    If you need more complex arguments, it can be a good idea to put some or all of them inside an object lookup:

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

    Python demonstrates how default and named arguments can be used to cover the most use cases in a more practical and graceful way than function overloading. JavaScript, not so much.

    0 讨论(0)
  • 2020-12-07 13:28

    Going further with eruciform's answer, you can chain your new call into your init method.

    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');
    
    0 讨论(0)
  • 2020-12-07 13:28
    export default class Order {
    
        static fromCart(cart) {
            var newOrder = new Order();
            newOrder.items = cart.items;
            newOrder.sum = cart.sum;
    
            return newOrder;
        }
    
        static fromOrder(id, order) {
            var newOrder = new Order();
            newOrder.id = id;
            newOrder.items = order.items;
            newOrder.sum = order.sum;
    
            return newOrder;
        }
    }
    

    Useges:

      var newOrder = Order.fromCart(cart)
      var newOrder = Order.fromOrder(id, oldOrder)
    
    0 讨论(0)
  • 2020-12-07 13:30

    Answering because this question is returned first in google but the answers are now outdated.

    You can use Destructuring objects as constructor parameters in ES6

    Here's the pattern:

    You can't have multiple constructors, but you can use destructuring and default values to do what you want.

    export class myClass {
    
      constructor({ myArray = [1, 2, 3], myString = 'Hello World' }) {
    
        // ..
      }
    }
    

    And you can do this if you want to support a 'parameterless' constructor.

    export class myClass {
    
          constructor({myArray = [1, 2, 3], myString = 'Hello World'} = {}) {
    
            // ..
          }
    }
    
    0 讨论(0)
提交回复
热议问题