为什么JavaScript ES6不支持多构造函数类?

时间:2015-09-17 09:09:46

标签: 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 = 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}

8 个答案:

答案 0 :(得分:27)

  

我想写下我的Javascript类

你不能以同样的方式超载标准功能。您可以做的是使用arguments对象来查询传递的参数数量:

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

Babel REPL Example

当然(使用您的更新示例),您可以采用您不关心参数数量的方法,而不是每个单独的值是否通过,在这种情况下,您可能会这样:

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

答案 1 :(得分:17)

你想要的是构造函数重载。 ECMAScript不支持这种情况以及function overloading的更一般情况。

ECMAScript不像更严格的语言那样处理缺少的参数。缺少参数的值保留为undefined,而不是引发错误。在这个范例中,很难/不可能检测出你想要的过载功能。

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

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

答案 2 :(得分:6)

这是基于arity(参数数量)的重载黑客攻击。我们的想法是使用不同的arities创建一个函数(通过查看fn.length确定)。

function overloaded(...inputs) {
  var fns = [];

  inputs.forEach(f => fns[f.length] = f);

  return function() {
    return fns[arguments.length].apply(this, arguments);
  };
}

var F = overloaded(
  function(a)    { console.log("function with one argument"); },
  function(a, b) { console.log("function with two arguments"); }
);

F(1);
F(2, 3);

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

答案 3 :(得分:5)

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



class Option {
  // Assign default values in the constructor object 
  constructor({key = 'foo', value, autoLoad = true} = {}) {
      this.key = key;
      // Or on the property with default (not recommended)
      this.value = value || 'bar';
      this.autoLoad = autoLoad;
      
      console.log('Result:', this);
  }
}

var option1 = new Option();
// Logs: {key: "foo", value: "bar", autoLoad: true}

var option2 = new Option({value: 'hello'});
// Logs: {key: "foo", value: "hello", autoLoad: true}




这对使用Typescript更有用,因为您可以使用传入的值确保类型安全(即key只能是字符串,autoLoad是布尔等。)

答案 4 :(得分:2)

从示例代码中猜测,您只需要为参数使用默认值:

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

答案 5 :(得分:1)

您可以使用静态方法,请查看my answer to same question

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

//a Instance that has b and c params
MyClass.BAndCInstance(b,c)

答案 6 :(得分:0)

将此参数与object.assigne一起使用

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

答案 7 :(得分:0)

这不是我想要的重载,但这是我如何通过创建具有一些不同初始化行为的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来说我还很陌生。可能不是最佳做法。