How to create Factory Functions instead of using Classes - javascript

I am using a javascript library that is implementing ES6 class in their modules. I have not used classical inheritance in javascript and would like to essentially "undo" their class implementation. Is there a way I can take those classes and still use them in a Factory/Composition approach. I want to take advantage of JS prototypal inheritance and easy compostability of objects. The following is an example of what I have so far. Ultimately I am trying to avoid using class and new, because I am not used to using it in JavaScript. Could anyone tell me if I am approaching this in the right way or if I am just wasting my time, thank you.
class Example {
constructor(id) {
this.id = id;
}
getID() {
console.log(this.id);
}
}
function convertClassToObject(theClass) {
var x = new theClass();
var newX = Object.create(x);
return newX;
}
var NewPrototype = convertClassToObject(Example);
function NewFactory(options) {
var x = Object.assign(Object.create(NewPrototype), options);
return x;
}
var NewInstance = NewFactory({id: 123456789});

You should rather get used to new, it's much simpler than doing prototypical inheritance in factories.
Of course, it's trivial to convert a constructor function to a factory function:
function classToFactory(constr) {
return (...args) => new constr(...args);
}
const makeExample = classToFactory(Example);
const newInstance = makeExample(123456789); // no `new` any more

Related

Is it possible to safely mix javascript class styles in an inheritance tree

I have picked up a piece of software which is fairly old and it has this form of "class" definition
function thisThing(parm1, parm2)
{
var self = new BaseThing(parm1);
self.val2 = parm2;
self.function2 = function() { ... }
return self;
}
I'd like to convert the whole hierachy to use the thisThing.prototype style of class, something like this
function thisThing(parm1, parm2)
{
var self = new BaseThing(parm1);
self.val2 = parm2;
return self;
}
thisThing.prototype = Object.create(BaseThing.prototype);
thisThing.prototype.constructor = thisThing;
thisThing.prototype = {
function2() { ... }
}
but I'm not sure if it is safe to mix the two styles.
Do I have to convert the whole hierarchy at once? Or can I do it a class at a time, and in which case do I need to do it top up, bottom down, or can I do it in the order I come across classes?
A note: Please don't suggest using ES6 classes, as they are not available in my current environment.
You've said that the old thisThing is called via new, which is good news in terms of whether you can mix things together (although we could work around it if not).
What you've shown as your desired form is quite non-standard, and thisThing.prototype is never used in it. I'm going to assume you mean you want to use standard constructor functions, which look like this:
function ThisThing(parm1, parm2) {
BaseThing.call(this, parm1);
this.parm2 = parm2;
}
ThisThing.prototype = Object.create(BaseThing.prototype);
ThisThing.prototype.constructor = ThisThing;
ThisThing.prototype.someMethod = function() {
// ...
};
Based on what you have in the question, you can go ahead and do that. (I do recommend the change in capitalization, it's the overwhelming standard for constructor functions.)
If there's any chance code might be calling it without new, you can make it tolerate that by detecting what's happened and handing off to new in the constructor:
function ThisThing(parm1, parm2) {
if (!(this instanceof ThisThing)) {
// Called without `new`; handle it
return new ThisThing(parm1, parm2);
}
BaseThing.call(this, parm1);
this.parm2 = parm2;
}
// ...
The thisThing you showed was using BaseThing as a constructor, so I assume (from that and the name) that it's already using the constructor pattern above.
You should be able to replace it like this. The only issue might be setting the param1 is a new BaseThing, so you might need to modify your old code.
by doing this you are using prototypical inheritance to get the methods of BaseThing.
Conversion like this can be mixed with your existing code with no problems so you can change one class at a time.
function ThisThing(param1, param2) {
this.val1 = param1
this.val2 = param2
}
ThisThing.prototype = new BaseThing
ThisThing.prototype.function2 = function() {}
var thing = new ThisThing(1, 2)
console.log(
thing instanceof BaseThing, // => true
thing instanceof ThisThing // => true
)

Javascript - transform object in class

I'm new in JS and i'm used to traditional OOP languages, so i'm having a hard time making some things work properly.
Here is my example :
var myObject = {
prop:'something';
callme:function () {
console.log('you called me');
}
}
firstObj = myObject;
firstObj.prop1 = 'new thing';
secondObj = myObject;
secondObj.prop1 = 'second thing';
Obviously the 'secondObj' overrides what 'fristObj' did before. How can i convert the 'myObject' object so it can work like a class , so i can create individual new instances of it ?
Thanks !
To create a 'class' in javascript you create a function which by convention has its first character capitalized.
function MyClass() { }
var obj = new MyClass();
To attach methods to this you add it to MyClass's prototype.
MyClass.prototype.callme = function () {
console.log('you called me');
}
To add properties use this to refer to this instance of the class.
function MyClass() {
this.prop = 'something';
}
So all together:
function MyClass() {
this.prop = 'something';
}
MyClass.prototype.callme = function () {
console.log('you called me');
}
// Remember to use var to declare variables (or they are global)
var firstObj = new MyClass();
firstObj.prop = 'new thing';
var secondObj = new MyClass();
secondObj.prop = 'second thing';
There is a style of JS programming where you just make objects and functions which return objects. In your case, make myObject into a function which returns the hash. It will return a new one each time it's called.
var myObject = function() {
return {
prop: 'something';
callme: function () {
console.log('you called me and prop is', this.prop);
}
};
}
firstObj = myObject();
firstObj.prop1 = 'new thing';
firstObj.callme();
secondObj = myObject();
secondObj.prop1 = 'second thing';
secondObj.callme();
In addition to the two good answers you already have, I wanted to point out that if you are ready to use edge stuff, ES6, the next JavaScript spec, includes classes.
Using transpilers like babel, you can already write ES6 code then compile it so that it can run on all browsers. It works increadibly well, especially when combined with tools like webpack that automates the process, and raises more and more adepts. It is the future, and clearly worse a try (classes are just the tip of the iceberg).
You can read more on ES6 classes here. Here is one of the example they give:
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
get area() {
return this.calcArea()
}
calcArea() {
return this.height * this.width;
}
}
A theoretical answer to a practical question. JavaScript is more traditional (take for example SmallTalk - one of the JavaScript grandparents) in terms of OOP than most of the current OOP languages. It is prototype-based, meaning that objects inherit from other objects. The constructor function is an unpleasant legacy (also called "classical inheritance") for the sake of typical OOP class imitation (in the way class is just a fabric for objects in most popular OOP, the typical JavaScript object is a fabric for other object). Analogous example could be the Io language (given for simplicity). IMO there is no need for separate objects' fabrics like class.

Understanding prototypal inheritance javascript

This is sort of a follow up of from this question: Python like inheritance for JavaScript
But I phrased it wrong and made it seem like I wanted classical inheritance in JavaScript when I just wanted to figure out how to do it similarly to Python.
This is what I have so far but it isn't working as I would like it to.
var util = require("util")
function FirstClass() {
this.name = "First Class";
}
FirstClass.prototype.sayName = function(){
this.callFunction("some_function", "hello")
}
FirstClass.prototype.callFunction = function(){
var func = arguments[0];
var args = Array.prototype.slice.call(arguments).slice(1, arguments.length)
if (this[func] !== undefined){
this[func].apply(null, args);
}
}
function SubClass(){}
util.inherits(SubClass, FirstClass)
SubClass.prototype.some_function = function(msg){
console.log(msg, this.name) // "hello undefined"
}
var sub_class = new SubClass();
sub_class.sayName();
When I try sub_class.sayName() It calls correctly and inherited sayName right, but when I try using the this keyword to show the name it doesn't work and prints undefined next to 'hello', so how would I fix it so it will show 'hello FirstClass'?
I was thinking this have all the variables and objects that FirstClass has since it inherits from it but it doesn't. Is that how prototypal inheritance is suppose to work? If so is there any way I can view/change parent variables from the child class?
I've tried looking up prototypal inheritance for JavaScript to figure it out but I'm not quite grasping the concept since I'm use to classical inheritance. Does anyone know how to inherit from the parent class and change it's variables from a child class?
Also if anyone has a good link to look at so I can understand prototypal inheritance better for future references that would be great.
You are missing this part:
function SubClass(){
FirstClass.apply(this);
}
This would be the equivalent to a super invocation in traditional class inheritance.
Your problem lies here: this[func].apply(null, args);
It should read: this[func].apply(this, args);
Here is a simplified example of how to inherit and extend a class. I very highly recommend checking Javascript Design Patterns for much better examples of how to create Classes with inheritance.
Now, as I was not familiar with what util was supposed to be doing, this example demonstrates how to achieve the result with native JS and no helpers:
JSFiddle here: http://jsfiddle.net/YAj5R/
function FirstClass() {
this.name = "First Class";
}
FirstClass.prototype.sayName = function () {
this.callFunction("some_function", "hello")
}
FirstClass.prototype.callFunction = function () {
var func = arguments[0];
var args = Array.prototype.slice.call(arguments).slice(1, arguments.length)
if (this[func] !== undefined) {
this[func].apply(this, args);
}
}
function SubClass() {
var parent = new FirstClass();
// this is lightweight example of an "extend" method
for(var attr in parent) {
// if this subclass has not over-written an attr,
// copy the attributes of FirstClass to SubClass
if(!this[attr]) {
this[attr] = parent[attr];
}
}
return this;
}
SubClass.prototype.some_function = function (msg) {
console.log(msg, this.name);
}
var sub_class = new SubClass();
sub_class.sayName();

Should I use polymorphism in javascript?

I am a programmer who has programmed in several languages, both functional and OO oriented. I programmed some Javascript too, but never used (or had to use) polymorphism in it.
Now, as kind of a hobby project, I would like to port some apps that were written in Java and C# that heavily use polymorhpism to Javascript.
But at a first glance I read lots of 'It's possible but ...'
So is there an alternative to it?
An example of what I would like to write in JS in pseudolang :
abstract class Shape{ { printSurface() } ; }
class Rect : Shape() { printSurface() { print (sideA*sideB}}
class Circle : Shape() { printSurface() { print { pi*r*r }}
TheApp { myshapes.iterate(shape s) {s.printSurface() } }
So a classic polymorphic case : iterating over baseclass.
I would like to achieve this kind of behaviour. I know it is polymorhism, but are there any other 'patterns' that I am overlooking that achieve this kind of behaviour or should I study the inheritance possibilities in Javascript?
As said, JavaScript is a dynamic typed language based on prototypal inheritance, so you can't really use the same approach of typed languages. A JS version of what you wrote, could be:
function Shape(){
throw new Error("Abstract class")
}
Shape.prototype.printSurface = function () {
throw new Error ("Not implemented");
}
function Rect() {
// constructor;
}
Rect.prototype = Object.create(Shape.prototype);
Rect.prototype.printSurface = function() {
// Rect implementation
}
function Circle() {
// constructor;
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.printSurface = function() {
// Circle implementation
}
Then, in your app:
var obj = new Circle();
if (obj instanceof Shape) {
// do something with a shape object
}
Or, with duck typing:
if ("printSurface" in obj)
obj.printSurface();
// or
if (obj.printSurface)
obj.printSurface();
// or a more specific check
if (typeof obj.printSurface === "function")
obj.printSurface();
You cold also have Shape as object without any constructor, that it's more "abstract class" like:
var Shape = {
printSurface : function () {
throw new Error ("Not implemented");
}
}
function Rect() {
// constructor;
}
Rect.prototype = Object.create(Shape);
Rect.prototype.printSurface = function() {
// Rect implementation
}
function Circle() {
// constructor;
}
Circle.prototype = Object.create(Shape);
Circle.prototype.printSurface = function() {
// Circle implementation
}
Notice that in this case, you can't use instanceof anymore, so or you fallback to duck typing or you have to use isPrototypeOf, but is available only in recent browsers:
if (Shape.isPrototypeOf(obj)) {
// do something with obj
}
Object.create is not available in browser that doesn't implement ES5 specs, but you can easily use a polyfill (see the link).
The "pattern" in play here would be "interface". As long as all the objects in the myshapes collection implement the printSurface() method, you will be fine.
Since Javascript is a dynamically typed language, the objects in a collection don't need to be related at all.
i know this can be done with prototypes but i am not a master of using it. i prefer the object literal approach (easier to visualize and has a "private" scope)
//shape class
var shape = function() {
//return an object which "shape" represents
return {
printSurface: function() {
alert('blank');
},
toInherit: function() {
alert('inherited from shape');
}
}
};
//rect class
var rect = function() {
//inherit shape
var rectObj = shape();
//private variable
var imPrivate = 'Arrr, i have been found by getter!';
//override shape's function
rectObj.printSurface = function(msg) {
alert('surface of rect is ' + msg);
}
//you can add functions too
rectObj.newfunction = function() {
alert('i was added in rect');
}
//getters and setters for private stuff work too
rectObj.newGetter = function(){
return imPrivate;
}
//return the object which represents your rectangle
return rectObj;
}
//new rectangle
var myrect = rect();
//this is the overridden function
myrect.printSurface('foo');
//the appended function
myrect.newfunction();
//inherited function
myrect.toInherit();
//testing the getter
alert(myrect.newGetter());
​
As Weston says, if you don't have the need for inheritance then the duck-typed nature of a dynamic language such as Javascript gives you polymorphism since there is no requirement in the language itself for a strongly typed base class or interface.
If you do want to use inheritance and do things like calling a superclass's implementation easily then this can be achieved with prototypes or object literals as shown by Joeseph.
Another thing would be to look at Coffescript since this compiles down to Javascript giving you all the OO goodness in a simple syntax. It will write all of the bollerplate prototyping stuff for you. The disadvantage is that it adds this extra compilation step. That said writing a simple class hierarchy like your example above and then seeing what javascript pops out as a result helps show how it can all be done.
On another note. If you want to program Javascript in an OO style using classes, you could look into the many "class-systems" for Javascript. One example is Joose (http://joose.it).
Many client side frameworks implement their own class system. An example of this is ExtJS.

in javascript, how can you add / execute a new method to an object using private methods?

wish to extend define and/or execute new methods against an object using its private methods - exactly as if I were to define the method within the original declaration - except these new methods apply only to this object to be executed one time, not to the Klass itself.
for example:
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
var k = new Klass();
console.log( k.publicFn1() ); // prints 16
suppose I wish to create and/or execute a new method on Klass, sum2(), that will add 2 to the privateFn.
have tried the brain-dead
k.publicFn2 = function() { return privateFn()+2 }
console.log( k.publicFn2() );
and it makes perfect sense that it does not work, but what does?
as a note, since functions are very long, attempting to maintain the syntax of privateFn() rather than self.privateFn() - this might be asking too much, but one hopes.
There is no such thing as private in ECMAScript
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
privateFn is a local variable which publicFn1 has access to due to scoping rules (and closures).
You cannot access privateFn outside the scope of function Klass
If you want to access privateFn outside the scope of function Klass then you have to expose it through a proxy or inject it further up the scope chain.
A proxy would be something like
this._private = function() {
return privateFn;
}
Injecting further up the scope chain would be something like
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
this.uid = Klass.uid++;
Klass.instances[this.uid] = {
privateFn: privateFn
};
}
Klass.uid = 0;
Klass.instances = [];
k.publicFn2 = function() { return Klass.instances[this.uid].privateFn()+2 }
Both are ugly.
The reason they are ugly is because you are emulating classical OO
Please use prototypical OO instead.
Shameless prototypical OO plug
Javascript is a prototype-based object-oriented language. That means if you wish to user instance-specific variables, you can do it by extending the prototype object of that object. Using it any other way is unnatural and leads to problems such as yours that require an extreme hack to overcome. Why not just use the language as it was intended?
The correct structure of your code would be more like the following:
function Klass(nr) {
this.nr = nr;
};
Klass.prototype.publicFn = function() {
alert(this.nr);
};
var inst = new Klass(13);
inst.publicFn();
There are no private functions in JS and there won't be. You can "hack" the similar effect, but at the cost of either hacking something on your own or using other libraries.
It makes little sense to try to bend the language to suit you. Instead you should learn the language as it is.

Categories

Resources