简体   繁体   中英

ES6 class constructor arguments over require

When using ES6 classes, why wouldn't you pass in dependencies via the constructor instead of listing them as an import/require at the top: eg

class DEF {
  constructor(ABC) {
    this.abc = new ABC();
  }
}

instead of

const ABC = require('./abc');

class DEF {
  constructor() {
    this.abc = new ABC();
  }
}

I'm trying to understand the difference between these programming styles and the implications of both?

This is a form of Dependency Injection which might be useful in various cases. For example for testing.

Usually you do something like

const DefaultABC = require('./abc');

class DEF {
  constructor(ABC = DefaultABC) {
    this.abc = new ABC();
  }
}

And then provide custom ABC implementation in test files. This might be simpler than mocking modules or otherwise hijacking module resolution and loading.

Cause sometimes it makes sense to pass in different classes:

new Vehicle(/*for*/ Animal)
new Vehicle(/*for*/ Human)

In the first example, you can use different versions of ABC, providing they implement the same interface. That provides looser coupling than the latter with the downside that you need full knowledge of how DEF will use ABC internally to make sure the interfaces match.

In the second example, you don't have to worry about which version of ABC is used. Both classes are now coupled tightly to each other, with the advantage of only needing to know how DEF works, no knowledge of ABC needed.

So both 'styles' solve different problems imho.

I would use the first style when I want to be able to 'plug in' different optional components into DEF. But I will use the second style when I extend a class.

This is extremely use-case dependent. The question here is where lies the decision making?

If it is the job of you class to decide which prototype method to use to instantiate a new object? Or do you want the caller to decide what prototype method to use? These questions should be asked and thought through when designing the application and responsibilities should be assigned based on the design dissensions.

Take for example a simple addition:

1 + 1 //=> 2
1 + '1' //=> '11'

In the above case the decision making lies by the internals. I can't provide type of object to return. The only responsibility I have is providing the correct objects. You could weigh this against a fictional variant:

1.add(1, Number) //=> 2
1.add('1', Number) //=> 2
1.add(1, String) //=> '11'

Neither of the two is right or wrong.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM