代码之家  ›  专栏  ›  技术社区  ›  codeholic

多个构造函数的JavaScript模式

  •  80
  • codeholic  · 技术社区  · 15 年前

    8 回复  |  直到 15 年前
        1
  •  128
  •   bobince    15 年前

    如果希望函数根据传递给它的参数的数量和类型而表现出不同的行为,则必须手动嗅探它们。JavaScript很乐意调用参数个数大于或小于声明个数的函数。

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

    您还可以访问 arguments 作为一个数组,我想得到任何进一步的参数传入。

    如果需要更复杂的参数,最好将部分或全部参数放入对象查找中:

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

    Python演示了如何使用默认参数和命名参数,以比函数重载更实用、更优雅的方式覆盖大多数用例。JavaScript,没那么多。

        2
  •  46
  •   mahdi shahbazi    6 年前

        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)
    
        //an Instance that has b and c params
        const instanceWithBAndC = MyClass.BAndCInstance(b,c)
    
        //another example for b and d
        const instanceWithBAndD = MyClass.BAndDInstance(b,d)
    

    使用此模式可以创建多个构造函数

        3
  •  34
  •   daggett    4 年前

    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')
    
        4
  •  13
  •   Jacob McKay    10 年前

    我不想像bobince的回答那样手工操作,所以我完全取消了jQuery的插件选项模式。

    以下是构造器:

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

    以下是不同的实例化方法:

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

    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]}
    
        5
  •  10
  •   laughingbovine    10 年前

    更进一步的回答,你可以把你的 new 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');
    
        6
  •  7
  •   DalSoft    5 年前

    回答是因为这个问题是第一个返回的 但现在答案已经过时了。

    你可以用 Destructuring objects as constructor parameters in ES6

    模式如下:

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

    如果你想支持“无参数”构造函数,你可以这样做。

    export class myClass {
    
          constructor({myArray = [1, 2, 3], myString = 'Hello World'} = {}) {
    
            // ..
          }
    }
    
        7
  •  3
  •   eruciform    12 年前

    有时,参数的默认值对于多个构造函数就足够了。当这还不够的时候,我会尝试将大多数构造函数功能包装到一个init(otherparams)函数中,然后调用该函数。还可以考虑使用工厂概念来创建一个可以有效地创建所需其他对象的对象。

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

        8
  •  2
  •   Arsen Ablaev    5 年前
    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;
        }
    }
    

    用途:

      var newOrder = Order.fromCart(cart)
      var newOrder = Order.fromOrder(id, oldOrder)
    
        9
  •  0
  •   Simon Stanford    8 年前

    这是中多个构造函数的示例 Programming in HTML5 with JavaScript and CSS3 - Exam Ref .

    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"));
    
        10
  •  0
  •   Lucius Matos    4 年前

    我相信有两个答案。一个使用带有IIFE函数的纯Javascript来隐藏其辅助构造函数。另一种是使用NodeJS模块来隐藏其辅助构造功能。

    我将只展示带有NodeJS模块的示例。

    类Vector2d.js:

    
    
    /*
    
        Implement a class of type Vetor2d with three types of constructors.
    
    */
    
    // If a constructor function is successfully executed,
    // must have its value changed to 'true'.let global_wasExecuted = false;  
    global_wasExecuted = false;   
    
    //Tests whether number_value is a numeric type
    function isNumber(number_value) {
        
        let hasError = !(typeof number_value === 'number') || !isFinite(number_value);
    
        if (hasError === false){
            hasError = isNaN(number_value);
        }
    
        return !hasError;
    }
    
    // Object with 'x' and 'y' properties associated with its values.
    function vector(x,y){
        return {'x': x, 'y': y};
    }
    
    //constructor in case x and y are 'undefined'
    function new_vector_zero(x, y){
    
        if (x === undefined && y === undefined){
            global_wasExecuted = true;
            return new vector(0,0);
        }
    }
    
    //constructor in case x and y are numbers
    function new_vector_numbers(x, y){
    
        let x_isNumber = isNumber(x);
        let y_isNumber = isNumber(y);
    
        if (x_isNumber && y_isNumber){
            global_wasExecuted = true;
            return new vector(x,y);
        }
    }
    
    //constructor in case x is an object and y is any
    //thing (he is ignored!)
    function new_vector_object(x, y){
    
        let x_ehObject = typeof x === 'object';
        //ignore y type
    
        if (x_ehObject){
    
            //assigns the object only for clarity of code
            let x_object = x;
    
            //tests whether x_object has the properties 'x' and 'y'
            if ('x' in x_object && 'y' in x_object){
    
                global_wasExecuted = true;
    
                /*
                we only know that x_object has the properties 'x' and 'y',
                now we will test if the property values ​​are valid,
                calling the class constructor again.            
                */
                return new Vector2d(x_object.x, x_object.y);
            }
    
        }
    }
    
    
    //Function that returns an array of constructor functions
    function constructors(){
        let c = [];
        c.push(new_vector_zero);
        c.push(new_vector_numbers);
        c.push(new_vector_object);
    
        /*
            Your imagination is the limit!
            Create as many construction functions as you want.    
        */
    
        return c;
    }
    
    class Vector2d {
    
        constructor(x, y){
    
            //returns an array of constructor functions
            let my_constructors = constructors(); 
    
            global_wasExecuted = false;
    
            //variable for the return of the 'vector' function
            let new_vector;     
    
            //traverses the array executing its corresponding constructor function
            for (let index = 0; index < my_constructors.length; index++) {
    
                //execute a function added by the 'constructors' function
                new_vector = my_constructors[index](x,y);
                
                if (global_wasExecuted) {
                
                    this.x = new_vector.x;
                    this.y = new_vector.y;
    
                    break; 
                };
            };
        }
    
        toString(){
            return `(x: ${this.x}, y: ${this.y})`;
        }
    
    }
    
    //Only the 'Vector2d' class will be visible externally
    module.exports = Vector2d;  
    
    

    useVector2d.js文件使用Vector2d.js模块:

    const Vector = require('./Vector2d');
    
    let v1 = new Vector({x: 2, y: 3});
    console.log(`v1 = ${v1.toString()}`);
    
    let v2 = new Vector(1, 5.2);
    console.log(`v2 = ${v2.toString()}`);
    
    let v3 = new Vector();
    console.log(`v3 = ${v3.toString()}`);
    
    

    终端输出:

    v1 = (x: 2, y: 3)
    v2 = (x: 1, y: 5.2)
    v3 = (x: 0, y: 0)
    

    这样我们就避免了脏代码(许多if和switch分布在整个代码中),难以维护和测试。每个建筑功能都知道要测试哪些条件。增加和/或减少建筑功能现在很简单。

    推荐文章