JavaScript has multiple ways of creating objects, and both novices and veterans can feel overwhelmed and unsure which one to use. The text introduces common patterns and best practices for common objects.

Object Literals: Object Literals

The easiest way to create an object is an object literal. JavaScript always boasts of being able to create objects “out of thin air” — no classes, no templates, no prototypes — just Poof! An object with methods and data appears.

Var o = {x: 42, y: 3.14, f: function () {}, g: function () {}};Copy the code

disadvantages

If you need to create an object of the same type elsewhere, you’ll have to copy and paste the object’s methods, data, and initialization code, resulting in a lot of duplicate code. You need a way to batch create objects of the same type, not just one object.

Factory mode: Factory Functions

This is the easiest way to create objects with the same structure, interface, and implementation. Instead of creating object literals directly, object literals are used as the return value of the function. This way, if you need to create objects of the same type more than once or in more places, you only need to call one function:

Function thing() {function thing() {x: 42, y: 3.14, f: function() {}, g: function() {}}; } var o = thing();Copy the code

disadvantages

This JavaScript object creation method can lead to memory bloat because each object contains a separate copy of the factory function. Ideally, we want each object to share only one copy of its functionality.

Constructor pattern

You can create objects of a specific type, like Array, Date, and other native JS objects. Its implementation method is as follows:

function Student(name,age){
    this.name=name;
    this.age=age;
    this.myName=function(){
        alert(this.name);
    };
}
var student1_ = new Student('aaa',15);
var student2_ = new Student('bbb',18);
Copy the code

disadvantages

Each instantiation of an object recreates all the methods in the constructor, and multiple instantiations can cause problems with memory overhead.

Prototype Chains

JavaScript provides a built-in mechanism for sharing data between objects called prototype chains. When an object’s properties are accessed, it can delegate to another object to fulfill the request. You can take advantage of this to modify the factory function so that each object it creates contains only its own unique data, while requests for other attributes are all delegated to a common object on the prototype chain:

var thingPrototype = {
  f: function() {},
  g: function() {}
};

function thing() {
  var o = Object.create(thingPrototype);

  o.x = 42;
  o.y = 3.14;

  return o;
}

var o = thing();
Copy the code

In fact, this is such a common pattern that the language already has built-in support for it. There is no need to create your own shared object (prototype object). Instead, a prototype object is automatically created for each function, where shared data can be placed:

thing.prototype.f = function() {};
thing.prototype.g = function() {};

function thing() {
  var o = Object.create(thing.prototype);

  o.x = 42;
  o.y = 3.14;

  return o;
}

var o = thing();
Copy the code

disadvantages

Can lead to duplication. The first and last lines of the above thing function are repeated almost identically in each “delegate prototype factory function”.

ES5类:ES5 Classes

You can isolate duplicate code by pulling it out and putting it in a custom function. This function creates an object, establishes a delegate (inheritance) relationship with the prototype of some other arbitrary function (parameter function), calls the function (parameter function) with the newly created object as an argument, and returns the new object.

function create(fn) { var o = Object.create(fn.prototype); fn.call(o); return o; } / /... Thing.prototype.f = function() {}; Thing.prototype.g = function() {}; function Thing() { this.x = 42; This. Y = 3.14; } var o = create(Thing);Copy the code

In fact, this is also a common pattern, and Javascript has some built-in support. The function defined by create is actually a basic version of the new keyword and can be replaced directly with new (constructor + prototype chain) :

Thing.prototype.f = function() {}; Thing.prototype.g = function() {}; function Thing() { this.x = 42; This. Y = 3.14; } var o = new Thing();Copy the code

In ES5, they are object creation functions that delegate shared data to prototype objects and rely on the new keyword to handle repeated logic.

disadvantages

Verbose and ugly, implementation inheritance is even more verbose and ugly.

ES6 Classes: ES6 Classes

In ES6 classes, performing the same operation provides clearer syntax:

class Thing { constructor() { this.x = 42; This. Y = 3.14; } f() {} g() {} } const o = new Thing();Copy the code

To compare

Over the years, JavaScript developers have had an uneasy relationship with the prototype chain. The two most likely ways to create objects today are class syntax, which relies heavily on stereotype chains, and factory function syntax, which does not rely on stereotype chains at all. The two styles differ in performance and functionality — though not by much.

performance

JavaScript engines are so heavily optimized today that it’s hard to extrapolate from JavaScript code what might be faster. The key is the measurement. Yet sometimes even measurement lets us down. Typically, updated JavaScript engines are released every six weeks, sometimes with significant performance changes, and any previous measurements we made and any decisions we made based on those measurements are immediately visible. Thus, the rule of thumb is to support the most official and widely-used syntax, assuming that it will be subjected to the most rigorous scrutiny and will be most efficient most of the time. The class syntax is by far the best for this, and is about three times faster than the factory pattern that returns literals.

The characteristics of

With the release of ES6, several of the differences that once existed between the class and factory patterns disappeared. Now, both factory patterns and classes can enforce truly private data:

  • The factory pattern is implemented through closures
  • Classes are implemented with Weak Maps

Both enable multiple inheritance — factory patterns can mix other properties into their objects, classes can mix other properties into their prototypes, or through class factories, or through proxies. Factory functions and classes can also return arbitrary objects when needed, and the syntax is simple.

conclusion

All things considered, the preference for JavaScript object creation is to use class syntax. It’s standard, it’s simple and clean, it’s fast, and it offers all the functionality that was once only available in factory mode