【问题标题】:Can you make multiple constructors in es6 and up?你能在 es6 及更高版本中创建多个构造函数吗?
【发布时间】:2020-11-17 22:52:12
【问题描述】:

问题

所以基本上我正在尝试创建一个具有多个构造函数的类,以便它对用户更加友好。但是当我运行代码时,它会输出:

SyntaxError: /FileSystem.js: Duplicate constructor in the same class (13:2)

我知道Creating multiple constructor in ES6 可以回答这个问题,但我的代码对每个构造函数都有不同的参数:

Varun Sukheja 的代码

    function Book() {
        //just creates an empty book.
    }
    
    
    function Book(title, length, author) {
        this.title = title;
        this.Length = length;
        this.author = author;
    }

我的代码

    class File
        constructor(Name, Type, Data) {
            this.Name = Name
            this.Type = Type
            this.Data = Data
      }
        constructor(FileName, Data) {
        let FileNameSplit = FileName.split('.').pop(); 
        this.Type = FileNameSplit[FileNameSplit.length - 1];
        
        let NameSplit = FileNameSplit.pop()
        this.Name = FileName;
        
        this.Data = Data
      }
    }

如您所见,我的代码有 2 个构造函数(一个带有 constructor(Name, Type, Data) { ,另一个带有 constructor(FileName, Data) { )。所以你可以看到使用 Saransh Kataria 的代码是行不通的。 .

Saransh Kataria 的代码

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

额外信息

IDE: 代码沙盒

浏览器: Chrome

完整代码:

    class File {
      /**
       * 
       * @param {String} Name Name Of File
       * @param {(String|Number)} Type File Type / Exstention
       * @param {Array} Data 
       */
        constructor(Name, Type, Data) {
            this.Name = Name
            this.Type = Type
            this.Data = Data
      }
        constructor(FileName, Data) {
        let FileNameSplit = FileName.split('.').pop(); 
        this.Type = FileNameSplit[FileNameSplit.length - 1];
        
        let NameSplit = FileNameSplit.pop()
        this.Name = FileName;
        
        this.Data = Data
      }
    }

    let Blob1 = new Blob([""])

    console.log(Blob1)

【问题讨论】:

  • JavaScript 中类中的方法不能重载,也就是说不能有多个同名的函数。要实现这样的目标,您需要执行类似于您提供的“Saransh Kataria”代码的操作。我不知道你的意思是“所以你可以看到使用 Saransh Kataria 的代码,不会工作。”,因为它会,你只需要更改 if 检查不同的长度

标签: javascript class es6-class


【解决方案1】:

Javascript 不支持定义多个构造函数。看来您只是在尝试进行函数重载。

在 Javascript 中,您不会这样做。相反,您使用您期望的最大参数数量声明版本,并动态测试 OP 传递的内容,并根据传递或未传递的内容调整您的行为。

您可以在此处查看 Javascript 中函数重载的一般描述:

How to overload functions in javascript?

如果您有多种不同版本的构造函数,那么您可以将其更改为只获取一个对象,然后在调用函数之前将所需的属性分配给该对象。然后,您的代码将询问该对象并查看传递的内容并相应地调整其行为。

例如,要同时支持这两个:

class File {
    constructor(Name, Type, Data) {
        this.Name = Name
        this.Type = Type
        this.Data = Data
  }
    constructor(FileName, Data) {
    let FileNameSplit = FileName.split('.').pop(); 
    this.Type = FileNameSplit[FileNameSplit.length - 1];
    
    let NameSplit = FileNameSplit.pop()
    this.Name = FileName;
    
    this.Data = Data
  }
}

您可以通过多种方式执行此类操作。最简单的是,如果所需参数的类型不同,并且我们不确切知道它们是什么类型。在不知道这些类型的情况下,我可能只是传入一个具有命名属性的对象:

class File
    constructor(options) {
       if (options.Name && options.Type) {
           this.Name = options.Name
           this.Type = options.Type
           this.Data = options.Data
       } else if (options.FileName && options.Data) {
           let FileNameSplit = options.FileName.split('.').pop(); 
           this.Type = FileNameSplit[FileNameSplit.length - 1];
    
           let NameSplit = FileNameSplit.pop()
           this.Name = options.FileName;
    
           this.Data = options.Data
       } else {
           throw new Error("improper arguments to File constructor);
       }
    }
}

仅供参考,在 Javascript 中,属性名称和参数名称以及常规变量名称通常以小写字母开头(我将代码保留为您已有的名称)。类名通常大写。


由于您知道 Data 参数是唯一的数组参数,因此您可以像这样动态检测传递了哪些参数:

class File {
    // args can be in either of these forms:
    // (Name, Type, Data)
    // (FileName, Data)
    constructor(Name, Type, Data) {
        if (Array.isArray(Data)) {
            // args must be (Name, Type, Data)
            this.Name = Name
            this.Type = Type
            this.Data = Data
        } else if (Array.isArray(Type)) {
            // args must be (FileName, Data)
            const FileName = Name;
            this.Name = FileName;
            this.Data = Type;
            let FileNameSplit = FileName.split('.').pop(); 
            this.Type = FileNameSplit[FileNameSplit.length - 1];
        } else {
            throw new TypeError("unexpected or missing arguments to File constructor")
        }
    }
}

【讨论】:

  • @user13592230 - 我添加了一个代码示例。如果你告诉我 5 个可能的参数的数据类型是什么,我可能也可以通过使用数据类型检测来编写不同的版本。
  • 如何使用静态/类方法来相应地初始化类。例如Book.empty()Book.novel(500_pages)都包装了不同参数的book实例的初始化?
  • @BKSpureon - 这些将被称为“工厂函数”(接受一组参数并构造一个新对象并将其返回给您的函数)。有适当的时间使用工厂功能。 IMO,它们不会像使用带有实际构造函数的new 那样使代码具有可读性,但如果它们对您来说更好,您可以这样做。仅供参考,在 Javascript 中动态检测传递的参数并根据传递的内容调整代码是非常常见的。 IMO,这是无类型语言的优点之一。
  • 好的,我会听取您对 javascript 类初始化的建议。
  • @BKSpureon - 由于您可能是这里的新手,如果这回答了您的问题,您可以通过单击答案左侧的复选标记向社区表明这一点。这也将为您在此处遵循正确的程序赢得一些声誉积分。
猜你喜欢
  • 2019-01-05
  • 2014-01-19
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-23
  • 2013-11-29
  • 1970-01-01
相关资源
最近更新 更多