Should I use polymorphism in javascript? - 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.

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
)

How to create Factory Functions instead of using Classes

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

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.

JavaScript OOP in NodeJS: how?

I am used to the classical OOP as in Java.
What are the best practices to do OOP in JavaScript using NodeJS?
Each Class is a file with module.export?
How to create Classes?
this.Class = function() {
//constructor?
var privateField = ""
this.publicField = ""
var privateMethod = function() {}
this.publicMethod = function() {}
}
vs. (I am not even sure it is correct)
this.Class = {
privateField: ""
, privateMethod: function() {}
, return {
publicField: ""
publicMethod: function() {}
}
}
vs.
this.Class = function() {}
this.Class.prototype.method = function(){}
...
How would inheritance work?
Are there specific modules for implementing OOP in NodeJS?
I am finding a thousand different ways to create things that resemble OOP.. but I have no clue what is the most used/practical/clean way.
Bonus question: what is the suggested "OOP style" to use with MongooseJS? (can a MongooseJS document be seen as a Class and a model used as an instance?)
EDIT
here is an example in JsFiddle please provide feedback.
//http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/
function inheritPrototype(childObject, parentObject) {
var copyOfParent = Object.create(parentObject.prototype)
copyOfParent.constructor = childObject
childObject.prototype = copyOfParent
}
//example
function Canvas (id) {
this.id = id
this.shapes = {} //instead of array?
console.log("Canvas constructor called "+id)
}
Canvas.prototype = {
constructor: Canvas
, getId: function() {
return this.id
}
, getShape: function(shapeId) {
return this.shapes[shapeId]
}
, getShapes: function() {
return this.shapes
}
, addShape: function (shape) {
this.shapes[shape.getId()] = shape
}
, removeShape: function (shapeId) {
var shape = this.shapes[shapeId]
if (shape)
delete this.shapes[shapeId]
return shape
}
}
function Shape(id) {
this.id = id
this.size = { width: 0, height: 0 }
console.log("Shape constructor called "+id)
}
Shape.prototype = {
constructor: Shape
, getId: function() {
return this.id
}
, getSize: function() {
return this.size
}
, setSize: function (size) {
this.size = size
}
}
//inheritance
function Square(id, otherSuff) {
Shape.call(this, id) //same as Shape.prototype.constructor.apply( this, arguments ); ?
this.stuff = otherSuff
console.log("Square constructor called "+id)
}
inheritPrototype(Square, Shape)
Square.prototype.getSize = function() { //override
return this.size.width
}
function ComplexShape(id) {
Shape.call(this, id)
this.frame = null
console.log("ComplexShape constructor called "+id)
}
inheritPrototype(ComplexShape, Shape)
ComplexShape.prototype.getFrame = function() {
return this.frame
}
ComplexShape.prototype.setFrame = function(frame) {
this.frame = frame
}
function Frame(id) {
this.id = id
this.length = 0
}
Frame.prototype = {
constructor: Frame
, getId: function() {
return this.id
}
, getLength: function() {
return this.length
}
, setLength: function (length) {
this.length = length
}
}
/////run
var aCanvas = new Canvas("c1")
var anotherCanvas = new Canvas("c2")
console.log("aCanvas: "+ aCanvas.getId())
var aSquare = new Square("s1", {})
aSquare.setSize({ width: 100, height: 100})
console.log("square overridden size: "+aSquare.getSize())
var aComplexShape = new ComplexShape("supercomplex")
var aFrame = new Frame("f1")
aComplexShape.setFrame(aFrame)
console.log(aComplexShape.getFrame())
aCanvas.addShape(aSquare)
aCanvas.addShape(aComplexShape)
console.log("Shapes in aCanvas: "+Object.keys(aCanvas.getShapes()).length)
anotherCanvas.addShape(aCanvas.removeShape("supercomplex"))
console.log("Shapes in aCanvas: "+Object.keys(aCanvas.getShapes()).length)
console.log("Shapes in anotherCanvas: "+Object.keys(anotherCanvas.getShapes()).length)
console.log(aSquare instanceof Shape)
console.log(aComplexShape instanceof Shape)
This is an example that works out of the box. If you want less "hacky", you should use inheritance library or such.
Well in a file animal.js you would write:
var method = Animal.prototype;
function Animal(age) {
this._age = age;
}
method.getAge = function() {
return this._age;
};
module.exports = Animal;
To use it in other file:
var Animal = require("./animal.js");
var john = new Animal(3);
If you want a "sub class" then inside mouse.js:
var _super = require("./animal.js").prototype,
method = Mouse.prototype = Object.create( _super );
method.constructor = Mouse;
function Mouse() {
_super.constructor.apply( this, arguments );
}
//Pointless override to show super calls
//note that for performance (e.g. inlining the below is impossible)
//you should do
//method.$getAge = _super.getAge;
//and then use this.$getAge() instead of super()
method.getAge = function() {
return _super.getAge.call(this);
};
module.exports = Mouse;
Also you can consider "Method borrowing" instead of vertical inheritance. You don't need to inherit from a "class" to use its method on your class. For instance:
var method = List.prototype;
function List() {
}
method.add = Array.prototype.push;
...
var a = new List();
a.add(3);
console.log(a[0]) //3;
As Node.js community ensure new features from the JavaScript ECMA-262 specification are brought to Node.js developers in a timely manner.
You can take a look at JavaScript classes. MDN link to JS classes
In the ECMAScript 6 JavaScript classes are introduced, this method provide easier way to model OOP concepts in Javascript.
Note : JS classes will work in only strict mode.
Below is some skeleton of class,inheritance written in Node.js ( Used Node.js Version v5.0.0 )
Class declarations :
'use strict';
class Animal{
constructor(name){
this.name = name ;
}
print(){
console.log('Name is :'+ this.name);
}
}
var a1 = new Animal('Dog');
Inheritance :
'use strict';
class Base{
constructor(){
}
// methods definitions go here
}
class Child extends Base{
// methods definitions go here
print(){
}
}
var childObj = new Child();
I suggest to use the inherits helper that comes with the standard util module: http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
There is an example of how to use it on the linked page.
This is the best video about Object-Oriented JavaScript on the internet:
The Definitive Guide to Object-Oriented JavaScript
Watch from beginning to end!!
Basically, Javascript is a Prototype-based language which is quite different than the classes in Java, C++, C#, and other popular friends.
The video explains the core concepts far better than any answer here.
With ES6 (released 2015) we got a "class" keyword which allows us to use Javascript "classes" like we would with Java, C++, C#, Swift, etc.
Screenshot from the video showing how to write and instantiate a Javascript class/subclass:
In the Javascript community, lots of people argue that OOP should not be used because the prototype model does not allow to do a strict and robust OOP natively. However, I don't think that OOP is a matter of langage but rather a matter of architecture.
If you want to use a real strong OOP in Javascript/Node, you can have a look at the full-stack open source framework Danf. It provides all needed features for a strong OOP code (classes, interfaces, inheritance, dependency-injection, ...). It also allows you to use the same classes on both the server (node) and client (browser) sides. Moreover, you can code your own danf modules and share them with anybody thanks to Npm.
If you are working on your own, and you want the closest thing to OOP as you would find in Java or C# or C++, see the javascript library, CrxOop. CrxOop provides syntax somewhat familiar to Java developers.
Just be careful, Java's OOP is not the same as that found in Javascript. To get the same behavior as in Java, use CrxOop's classes, not CrxOop's structures, and make sure all your methods are virtual. An example of the syntax is,
crx_registerClass("ExampleClass",
{
"VERBOSE": 1,
"public var publicVar": 5,
"private var privateVar": 7,
"public virtual function publicVirtualFunction": function(x)
{
this.publicVar1 = x;
console.log("publicVirtualFunction");
},
"private virtual function privatePureVirtualFunction": 0,
"protected virtual final function protectedVirtualFinalFunction": function()
{
console.log("protectedVirtualFinalFunction");
}
});
crx_registerClass("ExampleSubClass",
{
VERBOSE: 1,
EXTENDS: "ExampleClass",
"public var publicVar": 2,
"private virtual function privatePureVirtualFunction": function(x)
{
this.PARENT.CONSTRUCT(pA);
console.log("ExampleSubClass::privatePureVirtualFunction");
}
});
var gExampleSubClass = crx_new("ExampleSubClass", 4);
console.log(gExampleSubClass.publicVar);
console.log(gExampleSubClass.CAST("ExampleClass").publicVar);
The code is pure javascript, no transpiling. The example is taken from a number of examples from the official documentation.

JavaScript : Create new object of a custom class based on an existing one (adding methods to it)

I use the iOS UI Automation framework to make sure my iPhone app rocks.
Everybody who uses this framework would tell you that it's great, but that it's lacking a lot of structure.
So I have to deal with instances of UIAWindow, which represent different screens of my app. To be more object-oriented, I'd like to have a specific class for each screen, so I could add specific methods, like
myScreen1.tapDoneButton();
var total = myScreen2.getNumberOfElements();
For the moment, I'm able to achieve this by passing the instances of UIAWindow to functions that will add the appropriate methods, like this :
function makeMainScreen(actualScreen)
{
actualScreen.constructor.prototype.getAddButton = function() {
return this.buttons()["add button"];
};
actualScreen.constructor.prototype.tapAddButton = function() {
this.getAddButton().tap();
};
// Add any desired method...
return actualScreen;
}
It works fine, I use it like this :
var mainScreen = makeMainScreen(app.mainWindow());
mainScreen.tapAddButton();
But that doesn't seem object-oriented enough, I would like to create real objects, using the new and this keywords, so I'd have a declaration like this :
function MainScreen(actualScreen){
// This line doesn't work : because 'this' is immutable
this = actualScreen;
this.tapAddButton = function(){
this.getAddButton().tap();
}
//...
}
And I'd use it like this :
var mainScreen = new MainScreen(app.mainWindow());
mainScreen.tapAddButton();
I thought I could save the actualScreen as a property of the object (Like in Grace Shao's answer below), and call all the methods on it, but I'd like keep the original UIAWindow methods.
Does anybody know how to do this?
Or perhaps what I'm trying to achieve doesn't make sense, in which case I'd be happy to know.
If I understand correctly, you could try the following:
function MainScreen(actualScreen){
this.screen = actualScreen;
}
MainScreen.prototype.tapAddButton = function () {
this.screen.getAddButton().tap();
};
MainScreen.prototype.getScreen = function () {
return this.screen;
};
//...
var mainScreen = new MainScreen(app.mainWindow());
mainScreen.tapAddButton();
You are correct that you cannot assign anything to this. You could also define the methods inside the constructor MainScreen, but they would be considered privileged members.
function MainScreen(actualScreen){
this.screen = actualScreen;
this.tapAddButton = function () {
this.screen.getAddButton().tap();
};
}
If you dont want them to be privileged members, it is better to define them outside the constructor. Otherwise, the members will be initialized over and over again everytime when you instantiate a new object.
Updated:
You could also wrappers for the methods of screen inside the constructor as below.
var prop;
for (prop in actualScreen) {
if (typeof actualScreen[prop] !== 'Function') {
continue;
}
this[prop] = function () {
return actualScreen[prop].apply(actualScreen, arguments);
};
}

Categories

Resources