I am a huge fan of the pattern of exporting a function as the main API of a JavaScript module. The reason is that in JS, a function can do basically anything a typical object can do and then some.
So this is typical for me:
function stuff() {}
function thing() { /* shortcut or default behavior */ }
thing.stuff = stuff;
module.exports = thing;
Now I've run into a situation where I want thing to behave like an instance of EventEmitter. And I don't want it to be a constructor.
Why? Well thing will really be along the lines of osPreferences, where calling it with some options will save data to the disk. It doesn't make any sense for users to instantiate it. There wouldn't be much use for new OSPreferences(), since your computer can only respect one set of preferences at a time.
Yet, changes can happen at any time, outside of my API. So there is a huge benefit to:
osPreferences.on('change', fn);
So the question is, what is a solid pattern for assimilating the behavior of an EventEmitter instance? Is it good enough to simply loop through all properties of a throwaway instance and copy them to the target function? Is it worth trying to mimic the inherited vs non-inherited setup? Are there any weird cases to take into account, given that the default this would be changed? Or is there a better, more sensible way?
Is it good enough to simply loop through all properties of a throwaway instance and copy them to the target function?
Yes. You don't even need to create a throwaway instance, you can just copy all EventEmitter.prototype methods onto your function, and then apply the EventEmitter to it.
function osPreferences() { … }
for (var p in EventEmitter.prototype)
osPreferences[p] = EventEmitter.prototype[p];
EventEmitter.call(osPreferences);
Is it worth trying to mimic the inherited vs non-inherited setup?
Not really. You insist on a singleton usage of your api, so you don't need any inheritance at all.
Are there any weird cases to take into account, given that the default this would be changed?
No, EventEmitter is coded quite defensively. Of course, your listeners might find it unusual…
Looping through and copying the methods and properties of the original object can fail depending on how EventEmitter is implemented. This approach is most likely to fail when there is heavy use of closures to hide properties.
The best approach, in my opinion, is to just directly set the prototype on your function instance. With your example, it would be something like:
var OSPreferences = function(){
// ...
};
Object.setPrototypeOf(OSPreferences, new EventEmitter());
ES6 class syntax is the most elegant solution for subclassing.
let EventEmitter = require('events'); //or `require('events').EventEmitter` in nodejs
Class osPreferences extends EventEmitter{
constructor(){
super();
console.log(this);
}
}
let osp = new osPreferences();
osp.on('change',function(){
console.log('osPreferences changed');
});
osp.emit('change');
Unfortunately, latest Node version does not support class syntax. You have to use iojs instead.
Related
For closures which main goal it's to create another functions, I was wondering if in modern javascript, it's better to just use classes in modern javascript.
// Closure way private counter
const countPlusOne = () => {
let count = 0;
return () =>{
count++;
console.log(count);
}
}
let demoAdd = countPlusOne();
demoAdd(); // 1
demoAdd(); // 2
demoAdd(); // 3
To be honest, I never liked the use of closures in that way (but I think they're great for things like middlewares) as are hard to read.
So, should I refactor closures like the one up, to classes? Their behavior seem more analogous to typical Objects from other languages.
// Class way private counter
class countPlusClass{
count = 0;
add(){
this.count++;
console.log(this.count)
}
}
const demo = new countPlusClass();
demo.add(); // 1
demo.add(); // 2
demo.add(); // 3
No, classes aren't always better. They're just different. I'd say the main differences are
the interface of the thing returned by the constructor/factory function. A class instance has properties and methods, and usually multiple of them, whereas a closure is simply a function that you can call - with a single functionality. The syntax to invoke them is different, the extra method name is sometimes superfluous and sometimes beneficial.
In OOP, objects are expected to have an identity and a state. In FP, functions are expected to be pure. Sure, you don't need to follow a specific paradigm, and stateless objects are fine as are impure functions (though maybe call them "procedures" then), but keep these conventions in mind when arguing about readability and maintainability.
So choose wisely. Do you (possibly in the future) need multiple methods? Do you encapsulate state? Then use a class to create objects. Do you only need a function to call? Then create a closure.
A closure has a significant advantage over a class the way you're imagining: with a class, if you use a public class field like you are, any code with access to the instance can modify its value. This is usually undesirable - scope should generally be constrained as possible and you don't want the correctness of your class to depend on consumers of the class not modifying it (whether accidentally or deliberately).
class countPlusClass{
count = 0;
add(){
this.count++;
console.log(this.count)
}
}
const demo = new countPlusClass();
demo.add(); // 1
demo.add(); // 2
// some code elsewhere in the codebase that has access to the demo instance:
demo.count = 55555;
demo.add(); // not 3...
Closures, in contrast, are completely private (barring strange, exceptional circumstances).
If you were to use a class, and you wanted to emulate the privacy of closures, make sure to use private class fields instead, so they can't be modified outside the class.
class countPlusClass{
#count = 0;
add(){
this.#count++;
console.log(this.#count)
}
}
const demo = new countPlusClass();
demo.add(); // 1
demo.add(); // 2
// some code elsewhere in the codebase that has access to the demo instance
// cannot modify the private field
demo.count = 55555;
demo.add(); // not 3...
As for which is better, a closure-based object or a class? That's up to each individual developer.
Classes are not always better. It really depends upon the circumstances. Each has their place in your programming toolset.
A class has the following advantages:
There's defined syntax in the language
You can sub-class a class to extend it
You can more easily have many properties and many methods.
Methods are automatically non-enumerable and run in strict mode.
The syntax in the code that uses a class somewhat self-describes what is happening since new countPlusClass() makes it clear you're creating an object that will then have methods and probably state. That's not as obvious with the closure you show.
For object with a lot of methods there's some space-savings benefit to the prototype that a class uses.
Developer tools will recognize an instance of a class and know how to display it, auto-complete when typing code for it, how to represent it in the debugger, how to use it in error messages, etc...
A closure has these advantages:
The data in the closure is complete private. Nobody can get to it from outside the closure.
In some circumstances, the caller may find it takes less code to use the closure since you make one function call (sometimes passing arguments) and you get back another function that then implements the one thing this is supposed to do (your mention of middleware comes to mind).
So, I'd say that if you want or need or value any of the benefits of the class, then use the class.
If you don't want or need any of the benefits of the class and the simpler interface of the closure meets your needs or if you really need the privacy of the closure, then you can choose the closure.
I'd say that for a given circumstance, one of these tools may be a better "fit" for the problem at hand.
As has been mentioned in the comments, you can also have factory functions that may be closures (retain private state in a closure) and may return an object with methods and/or properties that can even be an object created by instantiating a class. So, these concepts can all be combined too to get some of the benefits of both.
Having read this article https://www.toptal.com/javascript/es6-class-chaos-keeps-js-developer-up and subsequently "JavaScript: The Good Parts", I shall henceforth commit to becoming a better JavaScript developer. However, one question remained for me. I usually implemented methods like this:
function MyClass(){
this.myData = 43;
this.getDataFromObject = function(){
return this.myData;
}
}
MyClass.prototype.getDataFromPrototype = function(){
return this.myData;
}
var myObject = new MyClass();
console.log(myObject.getDataFromObject());
console.log(myObject.getDataFromPrototype());
My assumption that underlies this whole post is that getDataFromObject is faster (during call, not during object creation) because it saves an indirection to the prototype but it is also less memory-efficient because every object gets an own instance of the function object. If that is already wrong, please correct me and you can probably stop reading here.
Else: Both article and book recommend a style like this:
function secretFactory() {
const secret = "Favor composition over inheritance [...]!"
const spillTheBeans = () => console.log(secret)
return {
spillTheBeans
}
}
const leaker = secretFactory()
leaker.spillTheBeans()
(quote from the article, the book didn't have ES6 yet but the ideas are similar)
My issue is this:
const leaker1 = secretFactory()
const leaker2 = secretFactory()
console.log(leaker1.spillTheBeans === leaker2.spillTheBeans) // false
Do I not mostly want to avoid that every object gets an own instance of every method? It might be insignificant here but if spillTheBeans is more complicated and I create a bazillion objects, each with twelvetythousand other methods?
If so, what is the "goot parts"-solution? My assumption would be:
const spillStaticBeans = () => console.log("Tabs rule!")
const spillInstanceBeans = (beans) => console.log(beans)
function secretFactory() {
const secret = "Favor composition over inheritance [...]!"
return{
spillStaticBeans,
spillInstanceBeans: () => spillInstanceBeans(secret)
}
}
const leaker1 = secretFactory()
const leaker2 = secretFactory()
leaker1.spillStaticBeans()
leaker2.spillInstanceBeans()
console.log(leaker1.spillStaticBeans === leaker2.spillStaticBeans) // true
console.log(leaker1.spillInstanceBeans === leaker2.spillInstanceBeans) // false
The spillInstanceBeans method is still different because each instance needs its own closure but at least they just wrap a reference to the same function object which contains all the expensiveness.
But now I have to write every method name two to three times. Worse, I clutter the namespace with public spillStaticBeans and spillInstanceBeans functions. In order to mitigate the latter, I could write a meta factory module:
const secretFactory = (function(){
const spillStaticBeans = () => console.log("Tabs rule!")
const spillInstanceBeans = (beans) => console.log(beans)
return function() {
const secret = "Favor composition over inheritance [...]!"
return{
spillStaticBeans,
spillInstanceBeans: () => spillInstanceBeans(secret)
}
}
}())
This can be used the same way as before but now the methods are hidden in a closure. However, it gets a bit confusing. Using ES6 modules, I could also leave them in module scope and just not export them. But is this the way to go?
Or am I mistaken in general and JavaScript's internal function representation takes care of all this and there is not actually a problem?
My assumption that underlies this whole post is that getDataFromObject is faster to call than getDataFromPrototype because it saves an indirection to the prototype
No. Engines are very good at optimising the prototype indirection. The instance.getDataFromPrototype always resolves to the same method for instances of the same class, and engines can take advantage of that. See this article for details.
Do I not mostly want to avoid that every object gets an own instance of every method? It might be insignificant here
Yes. In most of the cases, it actually is insignificant. So write your objects with methods using whatever style you prefer. Only if you actually measure a performance bottleneck, reconsider the cases where you are creating many instances.
Using ES6 modules, I could also leave them in module scope and just not export them. But is this the way to go?
Yes, that's a sensible solution. However, there's no good reason to extract spillInstanceBeans to the static scope, just leave it where it was - you have to create a closure over the secret anyway.
The spillInstanceBeans method is still different because each instance needs its own closure but at least they just wrap a reference to the same function object which contains all the expensiveness.
It should be noted that you're just replicating the way the JavaScript VM works internally: a function like spillTheBeans is compiled only once where it occurs in the source code even if it has free variables like secret. In SpiderMonkey for example, the result is called a »proto-function« (not to be confused with prototype). These are internal to the VM and cannot be accessed from JavaScript.
At runtime, function objects are created by binding the free variables of proto-functions to (a part of) the current scope, pretty much like your spillInstanceBeans example.
Saying that, it's true that using closures instead of prototype methods and this creates more function objects overall – the robustness gained from true privacy and read-only properties might make it worthwhile. The proposed style focuses more on objects rather than classes, so a different design could emerge that cannot be compared directly to a class-based design.
As Bergi says, measure and reconsider if performance is more important in (some part of) your code.
In JavaScript, why would one want to attach properties directly to the constructor?
var Human = function() {};
Human.specie = "Homo Sapience";
I've got this question after looking at CoffeeScript‘s __extend helper function, which contains, among the lines:
for ( var key in parent ) {
if ( __hasProp.call( parent, key ) ) child[key] = parent[key];
}
which copies properties / methods to the subclassed object directly from the constructor object. But why would anybody do that?
Thanks!
(Edit: In its original form, the question asked about attaching properties to classes vs. attaching them to prototypes, so that's what I'm responding to.)
It's really more a matter of convention than anything else. If you write
Human::specie = "Homo sapiens"
(where Human::specie is CoffeeScript shorthand for Human.prototype.specie) then declare jane = new Human, then jane.specie will be "Homo sapiens" (unless you specifically set jane.specie to something else). In this case, that sounds desirable.
But in other cases, having a property shared across a large number of prototypes makes your code harder to understand. Let's say that you have a Logger class with a config object. If you attached that object to the prototype, then you could write code like this:
log = new Logger
log.config.destination = './foo'
This would change the destination of all Logger instances to './foo', because there's only one config object. If you want config to apply to all Logger instances, then you should attach it to the class proper, removing the ambiguity from the code above:
log = new Logger
Logger.config.destination = './foo'
In a game say you have an object called world. However there will only ever be one world in the game. This is theoretically the reason you would do this.
In short the answer to the question posted is name spacing. There are certain values that may have sense to be shared across your program and that semantically have to do with certain class. These functions and values could be just put in some variables, but attaching them to constructor function is practical in order to namespace them.
The best example is JavaScript Math class (for purists, I know it's not really a class, it's an object):
// There are constants
Math.E
Math.PI
Math.SQRT2
// And there are also methods
Math.ceil
Math.cos
Math.sin
So the methods and values (saved in constants) are always the same and they don't depend on instance that they are being called on and it makes no sense to have them on instances.
I have a set of classes that work together (I'm coding in javascript).
There is one parent class and a number of child classes that are instantiated by the parent class. I have a number of clients of these classes that each need to add one or more methods to the parent or child classes.
Rather than having each client inherit from these classes, which is doable but messy because of the child classes, I am having these clients pass functions into the parent class when they instantiate the main class.
The main class creates the methods dynamically and the clients can call the methods like they were there all along.
My questions are:
is this a sensible thing to do?
what would the design pattern be for what I am doing?
The strategy pattern is for situations where you get your 'strategy' at runtime. might be applicable here. Strategy in this case is a class that conforms to a behavior, i.e. has a method like 'execute' or whatever.
The decorator pattern also might apply. It is also a runtime pattern, but augments the class it is decorating at the method level.
So the Strategy pattern is good if you are choosing a class dynamically, and Decorator is good if you are only changing out the method implementation at runtime.
(I took the decorator part of this answer with permission from ircmaxell)
I must admit that patterns aren't my "thing" - but you can do exactly what you want to in javascript. It is how all of the frameworks accomplish that sort of things "extending" child "classes" (there are no classes in javascript).
If you are in the pure javascript world, you want to use:
foo.prototype.bar = function() {};
So you can call bar on any foo, and bar only exists in memory once - that is the same function is referenced in memory through every foo object. So be careful with any variables you might be referencing outside that scope.
Each library has their own plugin architecture to accomplish roughly the same goal (and they take care of some of the messiness/danger in prototype)
You should provide some code, so that we can get a feel for what exactly you're talking about.
As you haven't: I can only guess that you're not making use of prototypes. Prototypes would be the "correct" design pattern for "object-oriented" JavaScript.
When you add a function/property/whatever to the prototype of an object in JavaScript, all instances, new and old receive the function/property/whatever on their prototype.
Extending prototypes in JavaScript is very simple, and should never become messy. If it does, it probably means you're over-complicating it.
As hvgotcodes says, you are describing the Strategy Pattern, the way you would do this for your specific case, is not to use prototypes (thereby affecting all objects of your class.)
Instead you'd provide a member that accepts a function as it's value.
e.g.
function MyClass() {
this.myFunction = defaultFunction;
this.defaultFunction = function() {
// do something by default.
alert("using default");
}
this.doFunction = function() {
// something that calls myFunction.
this.myFunction();
}
}
---8< snip --------
// later on...
t = new MyClass();
t.doFunction(); // output 'using default'
t.myFunction = function(){
// do something specific with this instance, when myFunction is called.
alert("customized for this instance.");
}
t.doFunction(); // output 'customized for this instance.'
I want to write some Javascript classes which extend DOM nodes (so that I can then insert instances of my class directly into the DOM), but am having difficulty finding out which class/prototype I should inherit from.
E.g.:
function myExtendedElement() {
this.superclass = ClassA;
this.superclass();
delete this.superclass;
}
But what should ClassA be?
It's not a good idea to do this.
First of all, to inherit from DOM element, you need to have access to that element's prototype. The problem is that not all browsers provide access to prototypes of DOM elements. Newer Gecko and WebKit -based clients, for example, expose some of these prototypes as global objects - HTMLDivElement, HTMLElement, Element, Node, etc.
For example, plain DIV element usually has a prototype chain similar to:
HTMLDivElement.prototype -> HTMLElement.prototype -> Element.prototype
-> Node.prototype -> Object.prototype -> null
You can access any of them and extend or inherit from as desired. But again, even though you can, I strongly advise not to.
When browser doesn't expose these prototypes, you're pretty much out of luck. You can try retrieving them by following constructor property of DOM element itself -
document.createElement('div').constructor;
- but then there's no guarantee that element has constructor property (e.g. IE6 doesn't) and even if it does, that this property references "correct" object. If, after all, constructor does reference correct object, there's still no guarantee that this objects is allowed to be augmented at all. The truth is that host objects are allowed to implement completely bizarre behavior and do not even have to follow rules that native JS objects follow (you can find dozens of such examples in real life).
Second reason you want to avoid inheriting from DOM element prototypes is that mechanism of such inheritance is not really specified anywhere; it could be quirky, unpredictable and overall fragile and unreliable.
Yes, you can create a constructor that would initialize objects with proper prototype chain (i.e. having DOM prototype in it):
function MyDivElement(){}
MyDivElement.prototype = HTMLDivElement.prototype;
var myDiv = new MyDivElement();
typeof myDiv.appendChild; // "function"
- but this is as much as it goes, and usefulness of this whole approach becomes limited by having certain methods in prototype and nothing else -
typeof myDivElement.nodeName; // "undefined"
myDivElement.innerHTML = '<span>foo<\/span>';
myDivElement.childNodes; // Error
Until some standard specifies exact mechanism for inheriting from DOM prototypes (and browsers actually implement that mechanism), it's best to leave them alone, and perhaps try alternative approach - e.g. wrapper or decorator patterns rather than prototype one :)
Old Q but there's a better answer than "Do" or "Don't" now that IE6 is mostly defunct. First of all prototyping core ECMA endpoint-inheritance constructors like 'Array' is pretty harmless and useful if you do it properly and test to avoid breaking existing methods. Definitely stay away from Object and think real hard before messing with Function, however.
If you're sharing code between a lot of people/authors, or dealing with DOM uncertainty, however, it's typically better to create adapter/wrapper objects with a new factory method to use in an inheritance-scheme.
In this case I wrote document.createExtEl to create wrapped DOM elements whose accessible properties are all available via prototype.
Using the following, your "superclass" for divs would be HTMLExtDivElement (in this case globally available - ew, but it's just an example). All references to the original HTMLElement instance's available properties live inside the wrapper's prototype. Note: some old IE properties can't be passed as references or even accessed without throwing errors (awesome), which is what the try/catch is for.
You could normalize common properties by adding logic to put missing or standardized properties in right after the loop wraps instance-available properties but I'll leave that to you.
Now for the love of Pete, don't ever use my code to write some cascading 16-times inheritance foolishness and then implement in some ironically popular library we're all forced to deal with or I will hunt you down and loudly quote "Design Patterns" at you while throwing rotten fruit.
//Implementation just like document.createElement()
//document.createExtEl('div').tagName === 'DIV'
document.createExtEl = ( function(){ //returns a function below
var htmlTags = ['div','a'], //... add all the element tags you care to make extendable here
constructorMap = {},
i = htmlTags.length;
while(i--){
thisTag = htmlTags[i].toLowerCase();
constructorMap[ thisTag ] = function(){
var elObj = document.createElement(thisTag),
thisProto = this.constructor.prototype,
constructorName = 'HTMLExt' + thisTag.charAt(0).toUpperCase() + thisTag.slice(1) + 'Element';
alert(constructorName);
window[constructorName] = this.constructor; //adds a global reference you can access the new constructor from.
for(var x in elObj){ try{ thisProto[x] = elObj[x]; } catch(e){} }
}
}
//all of the above executes once and returned function accesses via closure
return function(tagName){
return new constructorMap[tagName.toLowerCase()]();
}
} )()
//Now in the case of a superclass/constructor for div, you could use HTMLExtDivElement globally
In 2020, you can easily create a custom element by extending HTML elements.
class AppDrawer extends HTMLElement {...}
window.customElements.define('app-drawer', AppDrawer);
// Or use an anonymous class if you don't want a named constructor in current scope.
window.customElements.define('app-drawer', class extends HTMLElement {...});
More info and reference: Custom Elements
You can simply add new functions to the DOM prototypes, eg.
Element.prototype.myNameSpaceSomeFunction = function(...){...}
Then myNameSpaceSomeFunction will exist on all elements.
I've found a hack that works... at least, it enables me to access the extended object properties via the DOM element and vice versa. But it's hardly elegant.
var DOMelement = document.getElementById('myID'); // or $('#myID')[0]; in jQuery
DOMelement.extended = new extensionClass(this);
function extensionClass(element) {
this.element = element;
...
}