In the era of ES6, we have more ways to create objects, and we can choose different ways to create objects in different scenarios. There are three main ways to build objects: class keywords, constructors, and factory functions. They are all means of creating objects, but they are different, and you need to choose for those differences when developing.

So first of all, what do these three methods look like

// Class keyword, a new ES6 feature
class ClassCar {
  drive () {
    console.log('Vroom! '); }}const car1 = new ClassCar();
console.log(car1.drive());


// constructor
function ConstructorCar () {}

ConstructorCar.prototype.drive = function () {
  console.log('Vroom! ');
};

const car2 = new ConstructorCar();
console.log(car2.drive());


// Factory function
const proto = {
  drive () {
    console.log('Vroom! '); }};function factoryCar () {
  return Object.create(proto);
}

const car3 = factoryCar();
console.log(car3.drive());
Copy the code

These methods are prototype-based, and all support the implementation of private variables in functions at construction time. In other words, these functions share most of the same characteristics and are even equivalent in many scenarios.

In Javascript, each function can return a new object. When it is not a constructor or class, it is called a factory function.

ES6 classes are really syntactic sugar for constructors (at least at this stage), so everything that follows applies to constructors as well as to ES6 classes:

class Foo {}
console.log(typeof Foo); // function
Copy the code

Constructors and benefits of ES6 classes

  • Most books teach you how to use classes and constructors
  • this‘is pointing to this new object.
  • Some people likenewReadability of keywords
  • There may be minor differences in details, but if there are no problems during development, don’t worry too much.

Constructors and disadvantages of ES6 classes

1. You need the new keyword

In ES6, constructors and classes need the new keyword.

function Foo() {
  if(! (this instanceof Foo)) {returnnew Foo(); }}Copy the code

In ES6, if you try to call a class function without the new keyword, a task is thrown. If you want something that doesn’t use the new keyword, you have to wrap it around the factory function.

2. Details during the instantiation process are exposed to external apis

All calls are tied tightly to the implementation of the constructor, and if you need to fiddle with the construction process yourself, that’s a big hassle.

3. The constructor does not follow the Open/Closed rule

Because of the details of the new keyword, the constructor violates the Open/Closed rule: the API should be Open to extension and avoid modification.

I have questioned the fact that classes and factory functions are so similar that upgrading a class function to a factory function doesn’t matter, but in JavaScript, it does.

If you start writing constructors or classes, but you start writing, and you find that you need the flexibility of factory functions, you can’t just change the simple function and walk away.

Unfortunately, if you’re a JavaScript programmer, converting the constructor into a factory function is a major operation:

// The original implementation:

// class Car {
// drive () {
// console.log('Vroom! ');
/ /}
// }

// const AutoMaker = { Car };

// Implement the factory function change:
const AutoMaker = {
  Car (bundle) {
    return Object.create(this.bundle[bundle]);
  },

  bundle: {
    premium: {
      drive () {
        console.log('Vrooom! ');
      },
      getOptions: function () {
        return ['leather'.'wood'.'pearl']; }}}};// The expected usage is:
const newCar = AutoMaker.Car('premium');
newCar.drive(); // 'Vrooom! '

// But because it is a library
// Many places still use it like this:
const oldCar = new AutoMaker.Car();

// This will result in:
// TypeError: Cannot read property 'undefined' of
// undefined at new AutoMaker.Car
Copy the code

In the example above, we started with a class and changed it to a factory function that can create objects based on a specific prototype. Such functions can be used for a wide range of interface abstractions and special needs customization.

4. Use the constructor to letinstanceofThere is a window of opportunity

The difference between constructors and factory functions is the Instanceof operator, which many people use to make sure their code is correct. But to be honest, this can be very problematic and it is advisable to avoid instanceof.

Instanceof lies.

// Instanceof is a prototype chain check // not a type check // this means that the check is context-dependent, // when stereotypes are dynamically reassociated, // you get this confusing situationfunction foo() {}
const bar = { a: 'a'}; foo.prototype = bar; // bar is an instanceof foo, the display is not console.log(bar instanceof foo); //false// Baz is clearly not an instance of foo, right? const baz = Object.create(bar); / /... Console. log(baz instanceof foo); // true. oops.Copy the code

Instanceof doesn’t check like other strongly typed languages do, it just checks the objects on the prototype chain.

It will fail in some execution contexts, such as when you change constructive.prototype.

Or maybe you start with a constructor or class, and then you extend it to another object, as in the factory function case above. Instanceof can also be problematic at this point.

All in all, Instanceof is another big change that constructors and factory functions call for.

The benefits of using classes

  • A convenient, self-contained keyword
  • A unique authoritative method to implement a class in JavaScript.
  • Good experience for other developers who have experience in class language development.

The disadvantages of using classes

All the bad things about constructors, plus:

  • useextendsCreating a problematic class with keywords is a big temptation for users.

Hierarchical inheritance of classes causes a number of well-known problems, including Fragile Base class (which can be broken by inheritance), Gorilla Banana problem (where objects mix complex contexts), Duplication by necessity, etc.

The other two methods can get you into these problems too, but using the extend keyword, circumstances dictate, will lead you down this path. In other words, it leads you to write code for an inflexible relationship, rather than code that is more reusable.

Benefits of using factory functions

Factory functions are more flexible than classes and constructors and do not lead people down the wrong path. It doesn’t ensnare you in a deep chain of succession. You can simulate inheritance in a number of ways

1. Return an arbitrary object with an arbitrary prototype

For example, you could create different instances from the same implementation, a media player could create instances for different media formats, using different apis, or an event library could be for DOM time or WS events.

Factory functions can also instantiate objects through execution context, benefit from object pooling, and have a more flexible inheritance model.

2. No worries about complex refactoring

You will never need to convert factory functions to constructors, so refactoring is unnecessary.

3. Nonew

You don’t use the new keyword to create new objects; you can handle the process yourself.

4. Standardthisbehavior

This is whatever this you’re familiar with, and you can use it to get the parent object. For example, in player.create(), this refers to a player, and you can also bind other this with call and apply.

5. NoinstanceofThe trouble of

6. Some people like the readable immediacy of writing without new.

Disadvantages of factory functions

  • There is no automatic processing of the prototype, and the factory function prototype does not ripple through the prototype chain.
  • thisDoes not automatically point to the new object in the factory function.
  • There may be minor differences in details, but if there are no problems during development, don’t worry too much.

conclusion

In my opinion, class may be a convenient keyword, but it doesn’t hide the fact that it can lead unsuspecting users into inheritance pits. Another risk is the possibility that in the future you will want to use the factory function, and you will have to make a very big change.

If you are working in a large team, if you are modifying a public API, you may be interfering with code that you do not have access to, so you should not be blind to the effects of modification functions.

The great thing about factory mode is that not only is it more powerful and flexible, it also encourages the entire team to make apis simpler, safer, and lighter.

Translated from: medium.com/javascript-…

By Eric Elliott

Translation: Dominic Ming