在 ES6 中创建多个构造函数

Creating multiple constructor in ES6

在 ES5 中,可以为 class 创建多个构造函数,同时使用原型保留两者的公共部分,如下所示

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

我想使用 ES6 class 和构造函数语法达到相同的结果

class Book{
    constructore (){}
}

Function/constructor ECMAScript 不支持重载。如果你仍然想破解它,你可以使用参数对象来做到这一点。

constructor(title, length, author) {
        if(!arguments.length) {
            // empty book
        }
        else {
            this.title = title;
            this.Length = length;
            this.author = author;
        }
    }

其实,确实可以为一个原型创建多个构造函数。你只需要看到原型 is not specialconstructor 属性。因此,可以创建多个构造函数如下:

const type = (prototype, constructor) =>
    (constructor.prototype = prototype, constructor);

const book = {
    flipTo(page) {
        this.page = page;
    },
    turnPageForward() {
        this.page++;
    },
    turnPageBackward() {
        this.page--;
    }
};

const EmptyBook = type(book, function EmptyBook() {
    this.constructor = EmptyBook;
    this.ISBN        = "";
    this.title       = "";
    this.author      = "";
    this.genre       = "";
    this.covering    = "";
    this.length      = -1;
    this.page        = 0;
});

const Book = type(book, function Book(title, author, length) {
    this.constructor = Book;
    this.ISBN        = "";
    this.title       = title;
    this.author      = author;
    this.genre       = "";
    this.covering    = "";
    this.length      = length;
    this.page        = 0;
});

只是给构造器起不同的名字。希望对您有所帮助。

您也可以通过使用带有扩展的 ES6 类 来绕过这个限制。

class Base{
    Foo;
    Bar;
}

class TypeA extends Base {
    constructor(value) {
        this.Foo = value;
    }
}

class TypeB extends Base {
    constructor(value) {
        this.Bar = value;
    }
}

我相信有两个答案。一种使用'pure' Javascript 和IIFE 函数来隐藏它的辅助构造函数。而另一个使用NodeJS模块也隐藏了它的辅助构造函数。

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

Class 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 遍布整个代码),难以维护和测试。每个建筑功能都知道要测试哪些条件。增加和/或减少您的建筑功能现在很简单。