The Prototype pattern

The Prototype pattern involves using plain objects to act as templates for other objects. The Prototype pattern extends this template object directly without fussing with instantiation via new or Constructor.prototype objects. You can think of it as similar to conventional constructor or Class patterns minus the constructor.

Typically, you'll first create an object to act as your template. This will have all of the methods and properties associated with your abstraction. In the case of an inputComponent abstraction, it may look like this:

const inputComponent = {
name: 'Input Component',
render() {
return document.createElement('input');
}
};
Note how inputComponent starts with a lowercase character. By convention, only constructor functions should be named with an initial capital letter.

Using our inputComponent template, we can then create (or instantiate) specific instances using Object.create:

const inputA = Object.create(inputComponent);
const inputB = Object.create(inputComponent);

As we've learned, Object.create(thePrototype) simply creates a new object and sets its internal [[Prototype]] property to thePrototype, meaning that any properties accessed on the new object will be looked for on thePrototype if they are not available on the object itself. As such, we can treat the resulting object just like any other classical instance, accessing properties as we would on instances resulting from the more conventional Constructor or Class patterns:

inputA.render();

For convenience, we could also introduce a method on inputComponent itself designed to do the object creation work:

inputComponent.extend = function() {
return Object.create(this);
};

This means that we can create individual instances with slightly less code:

const inputA = inputComponent.extend();
const inputB = inputComponent.extend();

And if we wish to create other types of inputs, then we can easily extend inputComponent, as we already have; add some methods to our the resulting object; and then offer that new object up for others to extend:

const numericalInputComponent = Object.assign(inputComponent.extend(), {
render() {
const input = InputComponent.render.call(this);
input.type = 'number';
return input;
}
});

To override a particular method and access its parent, as you can see, we need to reference and call it directly (InputComponent.render.call()). You may expect that we should be able to use super.render() but, unfortunately, super only refers to [[Prototype]] of the object (the home) on which the containing method is defined. And because Object.assign() effectively steals these methods off their home objects, super would refer to the wrong thing.

The Prototype pattern is rather confusingly named. As we've seen, both the conventional Constructor pattern and the newer Class pattern involve the prototype, so you may want to instead refer to this pattern as the Object Extension Pattern or even the No-Constructor Approach to Prototypal Inheritance. Whatever you decide, it's quite a rare pattern. The classical OOP patterns are usually favored.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.251.70