为什么';JavaScript ES6是否支持多构造函数类?

为什么';JavaScript ES6是否支持多构造函数类?,javascript,class,constructor,ecmascript-6,Javascript,Class,Constructor,Ecmascript 6,我想像下面这样编写我的Javascript类 class Option { constructor() { this.autoLoad = false; } constructor(key, value) { this[key] = value; } constructor(key, value, autoLoad) { this[key] = value; this.autoLoad =

我想像下面这样编写我的Javascript类

class Option {
    constructor() {
        this.autoLoad = false;
    }

    constructor(key, value) {
        this[key] = value;
    }

    constructor(key, value, autoLoad) {
        this[key] = value;
        this.autoLoad = autoLoad || false;
    }
}
我想如果我们能用这种方式写课文会很好。 预计会发生:

var option1 = new Option(); // option1 = {autoLoad: false}
var option2 = new Option('foo', 'bar',); // option2 = {foo: 'bar'}
var option3 = new Option('foo', 'bar', false); // option3 = {foo: 'bar', autoLoad: false}
我想像下面这样编写我的Javascript类

你不能,就像你不能像那样重载标准函数一样。您可以使用该对象查询传递的参数数:

class Option {
    constructor(key, value, autoLoad) {
        // new Option()
        if(!arguments.length) {
            this.autoLoad = false;
        }
        // new Option(a, [b, [c]])
        else {
            this[key] = value;
            this.autoLoad = autoLoad || false;
        }
    }
}

当然(在更新的示例中),您可以采用不关心参数数量的方法,而关心是否传递了每个值,在这种情况下,您可以这样做:

class Option {
    constructor(key, value, autoLoad) {
        if(!key) { // Could change this to a strict undefined check
            this.autoLoad = false;
            return;
        }
        this[key] = value;
        this.autoLoad = autoLoad || false;
    }
}

您需要的是构造函数重载。ECMAScript不支持这种情况,更一般的情况是

ECMAScript不像更严格的语言那样处理缺少的参数。缺少参数的值保留为
未定义
,而不是引发错误。在这个范例中,很难/不可能检测到您想要的是哪个重载函数

惯用的解决方案是使用一个函数,并让它处理所需的所有参数组合。对于最初的示例,您可以像这样测试
的存在:

class Option {
  constructor(key, value, autoLoad = false) {
    if (typeof key !== 'undefined') {
      this[key] = value;
    }
    this.autoLoad = autoLoad;
  }
}

下面是一个基于arity(参数数量)的重载的技巧。其思想是从具有不同算术数的多个函数中创建一个函数(通过查看
fn.length
确定)


当然,这需要大量的防弹和清理,但你明白了。然而,我认为将此应用于ES6类构造函数不会有太多运气,因为它们是不同颜色的马

另一个选项是允许构造函数获取绑定到类属性的对象:

类选项{
//在构造函数对象中指定默认值
构造函数({key='foo',value,autoLoad=true}={}){
this.key=key;
//或在具有默认值的属性上(不推荐)
this.value=值| |'bar';
this.autoLoad=自动加载;
log('Result:',this);
}
}
var option1=新选项();
//日志:{键:“foo”,值:“bar”,自动加载:true}
var option2=新选项({value:'hello'});

//日志:{key:“foo”,value:“hello”,autoLoad:true}
根据示例代码猜测,您只需为参数使用默认值:

class Option {
    constructor(key = 'foo', value = 'bar', autoLoad = false) {
        this[key] = value;
        this.autoLoad = autoLoad;
    }
}
话虽如此,构造函数重载的另一种替代方法是使用静态工厂。假设您希望能够从普通参数、包含相同参数的哈希、甚至JSON字符串实例化对象:

class Thing {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }

    static fromHash(hash) {
        return new this(hash.a, hash.b);
    }

    static fromJson(string) {
        return this.fromHash(JSON.parse(string));
    }
}

let thing = new Thing(1, 2);
// ...
thing = Thing.fromHash({a: 1, b: 2});
// ...
thing = Thing.fromJson('{"a": 1, "b": 2}');

您可以使用静态方法,请参见


使用
对象。使用带有此参数的参数分配

This={...this,...arguments}

这并不是我想要的重载,但这是我如何通过创建具有不同初始化行为的obj1来伪装自己的基本版本。我意识到我本可以像上面所说的那样扩展论点,但我已经有一组令人讨厌的论点和相对不同的数据源需要解构,这将真正扭曲我的目标;这让我的处境变得更干净了

class obj1{
  constructor(v1, v2){
    this.a = v1;
    this.b = v2;
  }
}

class obj1Alt{
  constructor(v1, v2){
    return new obj1(v1*2,v2*2);
  }
}

new obj1(2,4) // returns an obj1
new obj1Alt(2,4) // also returns an obj1

免责声明:我已经编程很长时间了,但我对JS还是相当陌生的;可能不是最好的做法。

为什么不这样做往往是一个毫无成效的问题。因为,事实并非如此。很多语言都没有,ES6并不是唯一的一种。你不需要重载构造函数。只需使用默认值声明
自动加载
。可能的重复项(在
中,除了多个定义是一个语法错误外,这没有什么不同),因为到目前为止JavaScript没有并且需要这样的概念(即重载)。为什么
constructor
应该是例外?几乎相同的问题:为什么JavaScript对象不允许为一个键指定多个值?如果他使用的是
class
,那么他使用的是ES6。ES6具有参数默认值。使用它们。@torazaburo:默认值不适合变量函数,尽管我们为什么如此坚决地拒绝使用参数默认值?@torazaburo我们不是。我正在回答如何模拟重载的问题。我可能错过了原始代码其他方面的一些优化,param defaults是我假设的可能是多个的优化之一。通常认为使用或双管道
|
来设置默认值不是好的做法。特别是因为es6支持it ootb。不是真的推荐它。但是出于好奇,你为什么说它慢,你如何定义“惯用语”?@Bardiharbow谢谢你的回答。我已经修改了我的答案,改为“黑客”而不是“一般解决方案”。我已经使用类似的东西很多年了,没有任何问题。虽然它增加了通话税,但提高了阅读效率。查看许多jQuery源函数,您会发现,对于许多jQuery源函数,前5-20行是根据调用的预期重载重新排列参数的——读起来很快,但读起来很糟糕。不错。在这里使用
newthis()
比在这里使用
newthis()
更好,因为这样会更安全(
this
可能会根据静态函数中的内容改变含义)更清晰?@Andrew我不得不反对,在这里使用
this
会使代码与它所属的类无关,可移植性更强,冗余更少,因为类在其定义中只命名了一次。如果类被扩展,它也应该避免问题。我想这真的取决于你如何使用它。您的示例中的静态构造函数相当通用,而我使用它的方式是特定于类的。我不确定我认为代码对类高级不可知,在这种情况下我只会使用重构。它可能需要更少的更改<
This={...this,...arguments}
class obj1{
  constructor(v1, v2){
    this.a = v1;
    this.b = v2;
  }
}

class obj1Alt{
  constructor(v1, v2){
    return new obj1(v1*2,v2*2);
  }
}

new obj1(2,4) // returns an obj1
new obj1Alt(2,4) // also returns an obj1