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.'
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.
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.
I'm developing a javascript library, composed by a main object, that works as a static Class and contains various objects that do the same thing.
I am having trouble finding the best way to refer to the objects in the documentation, as i am using jGrouse and it refers to them as Classes, like:
public Class myLibrary
None of these objects and it's children will have any primitive type variables nor will have any factory pattern associated so, they are not to be reinstantiated.
I can't show you a live example, but i'll try to put here an analogous one:
var myLibrary = {};
myLibrary.methodOne = function(){ ... };
myLibrary.methodTwo = function(){ ... };
// this is a sub-library that will encapsulate methods for Array type operations
myLibrary.Array = {};
myLibrary.Array.forEach = function(array, function(item));
(...)
// this is a sub-library that will encapsulate methods for Event type operations
myLibrary.Events = {};
(...)
So, i don't think it's correct to refer to myLibrary, myLibrary.Array and myLibrary.Events as Classes, for the obvious reason that they are not meant to be instantiated.
I reject the idea to call them Static Classes as Javascript isn't design to work with static classes per se.
I think Object and Inner Object or Static Object may not be the way to go also.
I'm looking for the best way to identify them in my public documentation, as for not to confuse unexperienced programmers nor insult the more advanced developers.
Any help?
thanx
Your probably looking for the term "namespace".
You really shouldn't worry so much about the correct word. The are all far too vague and have completely separate meaning is several different meanings in JavaScript sub cultures.
The important thing to say in documentation is that "The Event has these methods".
I want to see the method signatures, I want to see a high level description of what they do and I want to see an example.
I have an abstract class which gives specific 'base' behavior to multiple sub classes. I want to instantiate a Singleton inside this abstract class. Is it good practice to:
a) instantiate a class within an abstract class
b) do this with a Singleton (I know these may be frowned upon)
For clarity I will give an example, the method instantiating the Singleton is:
public function createErrorRepository(repositoryType:String):void {
this._errorFactory = ErrorFactory.getInstance();
this._errorRep = this._errorFactory.createErrorRepository(repositoryType);
}
I have abstract methods:
public function getTitle():String {
throw new IllegalOperationError("Error - getTitle functionality not supported");
}
Maybe i'm over thinking, but would be good to get some confirmation this is good practice?
Thanks
Chris
N.B I am using as3 but have tagged Java as well due to similarity.
is it good practice to:
a) instantiate a class within an abstract class
It probably depends on the design, but there is nothing wrong with creating an instance of a class within an abstract class if the instance is something that all of the subclasses should have. In Java this is done with protected fields if the subclasses need to access the fields.
b) do this with a Singleton
If the singleton is a heavy object (e.g. lots of fields, methods, and so on) which all the subclasses of the abstract class will need, then it's probably preferable to have only one instance shared among them. It looks like the ErrorRepository might well fit that description, as there doesn't seem to be a reason for multiple instances to exist.
One last thought: if you didn't write ErrorFactory, make sure that the errorFactory.createErrorRepository(repositoryType) method is returning the same instance in all cases. (Even if you did write it, it wouldn't be a bad idea to check. I speak from experience.)
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;
...
}