Based on my observation, the book that I am reading about JavaScript states that there's an OOP with JavaScript? It doesn't tell much about it, I mean it wasn't explained how to define a class. Can someone give me a sample snippet?
Thanks
JavaScript is Prototype based and not class based.
Prototype-based programming is a style
of object-oriented programming in
which classes are not present, and
behavior reuse (known as inheritance
in class-based languages) is performed
via a process of cloning existing
objects that serve as prototypes. This
model can also be known as class-less,
prototype-oriented or instance-based
programming. Delegation is the
language feature that supports
prototype-based programming.
I recommend this book for a concise, precise explanation of both how to use JS's prototypal inheritance as well as how to emulate classical OO inheritance in JS.
Any function in javascript can be used to create an object:
Example:
function MyPoint(x, y) {
this.x = x;
this.y = y;
this.distanceTo = getDistance;
}
function getDistance(p) {
var dx = this.x-p.x;
var dy = this.y-p.y;
return Math.sqrt(dx*dx + dy*dy);
}
var p0 = new MyPoint(1, 2);
var p1 = new MyPoint(2, 3);
window.alert('The distance is ' + p0.distanceTo(p1));
The following snippet may help you getting started with JavaScript's class-less, instance-based objects:
function getArea() {
return (this.radius * this.radius * 3.14);
}
function getCircumference() {
var diameter = this.radius * 2;
var circumference = diameter * 3.14;
return circumference;
}
function Circle(radius) {
this.radius = radius;
this.getArea = getArea;
this.getCircumference = getCircumference;
}
var bigCircle = new Circle(100);
var smallCircle = new Circle(2);
alert(bigCircle.getArea()); // displays 31400
alert(bigCircle.getCircumference()); // displays 618
alert(smallCircle.getArea()); // displays 12.56
alert(smallCircle.getCircumference()); // displays 12.56
Example from: SitePoint - JavaScript Object-Oriented Programming
Here are couple different ways
if (typeof FFX == "undefined") {
FFX = {};
}
//Static class
FFX.Util = ({
return {
method:function(){
}
})();
FFX.Util.method();
//Instance class
FFX.Util2 = ({
// private method
var methodA=function(){
alert("Hello");
};
return {
method:function(){
//Call private method
methodA();
}
});
var x= new FFX.Util();
x.method();
Another way
function MyClass(){
}
/* privileged functions */
MyClass.prototype.hello = function(){
alert("Hello");
}
Also you could see how jquery, prototype and alike handle classes and see if thats fits you needs.
There is no one standard way of doing OOP in JavaScript. Everyone uses slightly different class/instance systems and most books fudge the issue. See this question for discussion of ways to work with OO in JS and pick your favourite.
In JavaScript everything is a object. So even a function is a object. So in js (less then < version 2), function makes classes (which are first class objects themselves). Go here, here and herefor understanding better
Related
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
I'm currently working on a platform game engine using javascript and the HTML5 canvas.
I have an object, "platform" which looks something like this...
var platform = function(pid,px,py,pw,ph) {
//Some variables here... and then we have some functions
this.step = function() {
//Update / step events here
}
this.draw = function() {
//Drawing events here
}
//etc.
}
The step() function has all of the calculations for collision detection while the draw() function draws the platform.
What I want to do is make another object called movingPlatform. This will be almost identical to the current platform except for the fact this one moves.
Rather than copying all of the collision detection code I'd like to be able to extend movingPlatform from platform... and then be able to add some additional code into the step() function to the moving platform can... well... move.
Some additional information...
When the game loads, it generates the level using data from a CSV file. I have an array, platforms[] that stores all of the platforms within it.
So to create a platform it looks like this...
platforms.push(new platform(i,data[1],data[2],data[3],data[4]));
I then make the platforms perform their step and draw events during the game's main step and draw events.
i.e.
for(var i=0; i<platforms.length; i++) {
platforms[i].step();
}
Any help would be awesome. Thanks!
I would use the platform class as a "base" object for the moving platform object.
I would do this via the prototype which is JavaScript's implementation of object oriented programming.
More info here How does JavaScript .prototype work?
+ many more articles on the web
You can use Javascript prototype inheritance functionality:
var baseItem = {
push: function(){alert('push');},
pull: function(){alert('pull')}
}
var childItem = {}
childItem.prototype = baseItem;
childItem.push = function(){
//call base function
childItem.prototype.push.call(this);
//do your custom stuff.
alert('I did it again.');
}
childItem.push();
Fiddle
Rather than pure inheritance, here, I'd go with prototype-extension, unless you build some big, ugly factory, just for the sake of saying that "MovingPlatform" inherited from "Platform" in a pure sense, it's not really what you'd expect it to be.
There are a few concerns (cheating, for one), but if your objects are all based wholly around this, and you're okay with people potentially hacking away in the console, then you don't really have much to worry about.
First, understand what you're doing inside of Platform:
var MyObject = function (a) {
this.property = a;
this.method = function (b) { this.property += b; };
};
Every time you make a new MyObject, you're creating a brand new version of the .method function.
That is to say, if you make 10,000 of these, there will be 10,000 copies of that function, as well.
Sometimes that's a very good and safe thing.
It can also be a very slow thing.
The problem is, because everything in your object is using this, and because nothing inside of the function changes, there's no benefit to creating new copies -- just extra memory used.
...so:
MyObject = function (a) {
this.property = a;
};
MyObject.prototype.method = function (b) { this.property += b; };
var o = new MyObject(1);
o.method(2);
o.property; //3
When you call new X, where X has properties/methods on its prototype, those properties/methods get copied onto the object, during its construction.
It would be the same as going:
var method = function (b) { this.property += b; },
o = new MyObject(1);
o.method = method;
o.method(2);
o.property; // 3
Except without the extra work of doing it yourself, by hand.
The benefit here is that each object uses the same function.
They basically hand the function access to their whole this, and the function can do whatever it wants with it.
There's a catch:
var OtherObj = function (a, b) {
var private_property = b,
private_method = function () { return private_property; };
this.public_property = a;
this.unshared_method = function () { var private_value = private_method(); return private_value; };
};
OtherObj.prototype.public_method = function () {
return private_property;
};
var obj = new OtherObj(1, "hidden");
obj.public_property; // 1
obj.unshared_method(); // "hidden"
obj.public_method(); // err -- private_property doesn't exist
So assuming you don't have much you care about staying private, the easiest way of doing this would be to make reusable function, which rely on this, which you then give to multiple prototypes, through extension.
// collision-handling
var testCollision = function (target) { this./*...*/ },
handleCollision = function (obj) { this./* ... */ };
// movement-handling
var movePlatform = function (x, y, elapsed) { this.x += this.speed.x*elapsed; /*...*/ };
// not really the cleanest timestep implementation, but it'll do for examples
var Platform = function (texture, x, y, w, h) {
this.x = x;
// ...
},
MovingPlatform = function (texture, x, y, w, h, speedX, speedY, etc) {
this.etc = etc;//...
};
Platform.prototype.testCollision = testCollision;
Platform.prototype.handleCollision = handleCollision;
MovingPlatform.prototype. // both of the above, plus the movePlatform method
This is a lot by hand.
That's why functions in different libraries will clone or extend objects.
var bunchOfComponents = {
a : function () { },
b : 32,
c : { }
},
myObj = {};
copy(myObj, bunchOfComponents);
myObj.a();
myObj.b; //32
Your function-reuse goes up, while the horror of writing proper Class-based, hierarchical inheritance, with virtual-overrides, abstracts, and shared-private properties, by hand, goes down.
Getting inheritance right in Javascript is somewhat tricky if you're used to class-based languages.
If you're not sharing a lot of behaviours, you might find it easier to just create some shared methods, then make them available to objects of each platform type.
//Create constructors for each type
var Platform = function(pid,px,py,pw,ph) { //By convention, constructors should start with an uppercase character
...
}
var MovingPlatform = function() {
...
}
//Create some reuseable methods
var step = function() {
...
}
var draw = function() {
...
}
var move = function() {
...
}
//Attach your methods to the prototypes for each constructor
Platform.prototype.step = step;
Platform.prototype.draw = draw;
MovingPlatform.prototype.step = step;
MovingPlatform.prototype.draw = draw;
MovingPlatform.prototype.move = move;
...etc
That said, if you do want to build up a proper inheritance chain, there are plenty of articles available to help you: 1 2 3 4
In Javascript I would like to create two classes: A node, and a node list. A node contains some trivial properties; a node list contains pointers to a node, and multiple node lists can contain the same nodes. Would the following be correct (simplistic) design?
function Node(name, x, y) {
this.name = name;
this.x = x;
this.y = y;
}
Node.prototype.setX = function(x) {
this.x = x;
};
Node.prototype.setY = function(y) {
this.y = y;
};
function Nodelist() {
this.list = [];
}
Nodelist.prototype.addNode = function(node) {
this.list.push(node);
};
var a = new Node('stack', 0, 0);
var b = new Node('overflow', 0, 0);
var l = new Nodelist();
var m = new Nodelist();
l.addNode(a);
l.addNode(b);
m.addNode(a);
Do I even need these .prototype.set functions? Playing around in the console it seems I can just do a node.x = 10. Thanks.
not sure what your intention is (setters with no getters?), but you might be interested in private variables. to achieve the effect of private variables, you would start with the following:
function Guy(name) {
var _name = name;
this.getName = function(){ return _name; }
this.setName = function(n) { _name = n; }
}
var g = new Guy("Bob");
alert(g.getName()); // works
alert(g._name); // doesn't work
(In fact in this simple example, you don't even need the variable _name; getName and setName can close over the function argument name);
No, you don't need those functions, unless you need some sort of callback-based system where a function should be executed when the value changes. You can access and assign to the properties directly, as you discovered.
Javascript objects properties are accessible from anywhere ie. there are no real private variables so defining getter setter methods in this way is kind of pointless. If you want private variables or similar behaviour, read this http://javascript.crockford.com/private.html
It depends on if you're trying to enforce the encapsulation of x and y in an OOP manner. One way that javascript differs from - for example - Java is that it doesn't inherently enforce private variables. Usually, the common way to declare that some variable/method SHOULD be private is to name it with an underscore. So if you're actually trying to enforce OOP concepts here, then declare x and y like this:
function Node(name, x, y) {
this.name = name;
this._x = x;
this._y = y;
}
And then keep your setters. If you aren't trying to enforce some kind of encapsulation of x and y to your Node, then go ahead and don't provide them and just use the node.x/node.y when you need to get/set x or y.
Just keep in mind that this is simply a naming convention and when this script is running, _x is just as visible as x. It will be up to you and any programmers you work with to enforce this.
There seem to be many different ways of doing OO in JavaScript.
I like:
function ClassA(){};
ClassA.prototype={
someFunc:function(a,b,c){},
otherFunc:function(){}
}
var c=new ClassA();
and have never used features beyond what this provides (despite being a proficient OOer). I suspect this is old fashioned, because every so often I see new spangled variants, and it makes me wonder if I'm choosing the best approach. For instance, you can do magic in the constructor method to create private variables and accessor methods, something I believed (until relatively recently) to be impossible. What about subclassing? I wouldn't know how to achieve this, but it must have some sort of common pattern by now.
How do you do it and why?
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
return {
publicMethod: function() { alert(iAmAPrivateVariable); },
publicVariable: bar()
}
}
//usage
var thing = foo()
This is known as a functional appoach, since you are actually leveraging closures for encapsulation (which is the only way to do it in javascript).
In a general way, you shouldn't be doing OO in javascript, it isn't that great a language for it for a great many reasons. Think scheme with squiggly brackets and semi-colons, and you will start writing the language like the pros do. That being said, sometime OO is a better fit. In those cases, the above is typically the best bet
EDIT: to bring inheritance into the mix
function parent() {
return { parentVariable: 2 };
}
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
me = parent();
me.publicMethod = function() { alert(iAmAPrivateVariable); };
me.publicVariable = bar();
return me;
}
This makes things a tad more complected, but accomplishes the desired end result while still taking a functional approach to OO concepts (in this case, using decorator functions instead of real inheritance). What I like about the whole approach is we are still really treating objects the way they are intended to be in this kind of language -- a property bag you can attach stuff to at will.
EDIT2:
Just wanted to give credit where credit is due, this approach is a very slight simplification to what doug crockford suggests in Javascript: The Good Parts. If you want to take your js skills to the next level, I would highly suggest starting there. I don't think I have ever learned so much from such a small book.
Another note is this is wildly different then what you will see most of the time in most of the jobs you will ever work at, and often is very hard to explain a) what is going on, and b) why it is a good idea to coworkers.
Simple JavaScript Inheritance
Because John Resig said so.
"Subclassing" in JavaScript generally refers to prototype-based inheritance, which basically follows this pattern:
function Superclass() { }
Superclass.prototype.someFunc = function() { };
function Subclass() { }
Subclass.prototype = new Superclass();
Subclass.prototype.anotherFunc = function() { };
var obj = new Subclass();
This builds a "prototype chain" from obj -> Subclass.prototype -> Superclass.prototype -> Object.prototype.
Pretty much every OOP library for JavaScript builds upon this technique, providing functions that abstract most of the prototype "magic".
I think joose is a pretty cool way to do OOP in javascript
http://code.google.com/p/joose-js/
Objects in JavaScript are unlike almost all the other high-profile languages. Instead of being class-based (like in Java, C++, PHP, etc etc), they are prototype-based. As such, the basic paradigm of object-oriented programming has to be considerably modified. People who can't or don't want to re-think this and insist on using class-based thinking have to build class-based logic in JavaScript or use code from someone else who has already built it.
I like to do something like
// namespace "My"
var My = new function {
// private methods
/**
* Create a unique empty function.
* #return {Function} function(){}
*/
function createFn () {return function(){}}
/** A reusable empty function. */
function emptyFn () {}
/**
* Clone an object
* #param {Object} obj Object to clone
* #return {Object} Cloned object
*/
function clone (obj) { emptyFn.prototype=obj; return new emptyFn() }
// public methods
/**
* Merge two objects
* #param {Object} dst Destination object
* #param {Object} src Source object
* #param {Object} [options] Optional settings
* #return {Object} Destination object
*/
this.merge = function (dst, src, options) {
if (!options) options={};
for (var p in src) if (src.hasOwnProperty(p)) {
var isDef=dst.hasOwnProperty(p);
if ((options.noPrivate && p.charAt(0)=='_') ||
(options.soft && isDef) ||
(options.update && !isDef)) continue;
dst[p]=src[p];
}
return dst;
}
/**
* Extend a constructor with a subtype
* #param {Function} superCtor Constructor of supertype
* #param {Function} subCtor Constructor of subtype
* #param {Object} [options] Optional settings
* #return {Function} Constructor of subtype
*/
this.extend = function (superCtor, subCtor, options) {
if (!subCtor) subCtor=createFn();
if (!options) options={};
if (!options.noStatic) this.merge(subCtor, superCtor, options);
var oldProto=subCtor.prototype;
subCtor.prototype=clone(superCtor.prototype);
this.merge(subCtor.prototype, oldProto);
if (!options.noCtor) subCtor.prototype.constructor=subCtor;
return subCtor;
}
}
And then something like...
// namespace "My.CoolApp"
My.CoolApp = new function(){
// My.CoolApp.ClassA
this.ClassA = new function(){
// ClassA private static
var count=0;
// ClassA constructor
function ClassA (arg1) {
count++;
this.someParam=arg1;
}
// ClassA public static
My.merge(ClassA, {
create: function (arg1) {
return new ClassA(arg1);
}
}
// ClassA public
My.merge(ClassA.prototype, {
doStuff : function (arg1) {
alert('Doing stuff with ' + arg1);
},
doOtherStuff : function (arg1) {
alert('Doing other stuff with ' + arg1);
}
}
return ClassA;
}
// My.CoolApp.ClassB
this.ClassB = new function(){
My.extend(My.CoolApp.ClassA, ClassB);
// ClassB constructor
function ClassB () {
ClassA.apply(this, arguments);
}
return ClassB;
}
}
...the clone function is the key to inheritance. In short:
Clone an object by making it the prototype of a throwaway function and calling the function with 'new'.
Clone the parent constructor's prototype, and set it the result as the prototype of the child class.
OOP in Javascript for Canvas
Check out how useful OOP in js can be in a different situation... This lets you draw squares and circles as objects so that you can go back and loop over or manipulate them as you like.
function Shape(x,y,color){
this.x = x
this.y = y
this.color = color
}
function Square(height,width,color){
Shape.call(this, event.x, event.y, color)
this.height = height
this.width = width
this.x -= canvas.offsetLeft + (this.height/2)
this.y -= canvas.offsetTop + (this.width/2)
}
Square.prototype = new Shape();
Square.prototype.draw = function(color){
ctx.fillStyle = color
ctx.fillRect(this.x,this.y,this.height,this.width)
}
function Circle(color, width){
Shape.call(this)
this.x = event.x -60
this.y = event.y -60
this.width = width
}
Circle.prototype = new Shape();
Circle.prototype.draw = function(color){
ctx.beginPath()
ctx.arc(this.x,this.y,this.width,0,2*Math.PI, false);
ctx.fillStyle = color
ctx.fill()
}
I have the following code that creates two objects (ProfileManager and EmployerManager) where the object EmployerManager is supposed to inherit from the object ProfileManager.
However, when I do alert(pm instanceof ProfileManager); it returns false.
function ProfileFactory(profileType) {
switch(profileType)
{
case 'employer':
return new EmployerManager();
break;
}
}
function ProfileManager() {
this.headerHTML = null;
this.contentHTML = null;
this.importantHTML = null;
this.controller = null;
this.actions = new Array();
this.anchors = new Array();
}
ProfileManager.prototype.loadData = function(action, dao_id, toggleBack) {
var step = this.actions.indexOf(action);
var prv_div = $('div_' + step - 1);
var nxt_div = $('div_' + step);
new Ajax.Request(this.controller, {
method: 'get',
parameters: {action : this.actions[step], dao_id : dao_id},
onSuccess: function(data) {
nxt_div.innerHTML = data.responseText;
if(step != 1 && !prv_div.empty()) {
prv_div.SlideUp();
}
nxt_div.SlideDown();
for(i = 1; i <= step; i++)
{
if($('step_anchor_' + i).innerHTML.empty())
{
$('step_anchor_' + i).innerHTML = this.anchors[i];
}
}
}
}
)
}
EmployerManager.prototype.superclass = ProfileManager;
function EmployerManager() {
this.superclass();
this.controller = 'eprofile.php';
this.anchors[1] = 'Industries';
this.anchors[2] = 'Employer Profiles';
this.anchors[3] = 'Employer Profile';
this.actions[1] = 'index';
this.actions[2] = 'employer_list';
this.actions[3] = 'employer_display';
}
var pm = new ProfileFactory('employer');
alert(pm instanceof ProfileManager);
BTW, this is my very first attempt at Object-Oriented JavaScript, so if you feel compelled to comment on the stupidity of my approach please feel free to do so, but offer suggestions on how to approach the problem better.
I've been using something similar to Dean Edward's Base.js model.
http://dean.edwards.name/weblog/2006/03/base/
Prototype supports (mimicing) class inheritance via the Object.extend() function.
However, it could be argued that trying to impose class-based inheritance on a language which doesn't support classes is an example of "when you only have a hammer, the whole world looks like a nail".
Thanks for all of the comments. However, the solution to the problem was found in making this change to the declaration of the EmployerManager:
function EmployerManager() {
this.controller = 'eprofile.php';
this.anchors = new Array('Industries', 'Employer Profiles', 'Employer Profile');
this.actions = new Array('index', 'employer_list', 'employer_display');
}
EmployerManager.prototype = new ProfileManager;
Apparently JavaScript supports two different types of inheritance, function based and prototype based. The function based version is what I originally posted but could not make work because the EmployerManager could not see the loadData method that was part of ProfileManager's prototype.
This new example is prototype based and works now. EmployerManager is now an instance of ProfileManager.
In your code, pm is an instance of EmployerManager that has a superclass of ProfileManager. That seems backwards to me. Shouldn't ProfileManager have a superclass of EmployerManager?
I just wanted to interject that while JavaScript is an object oriented language, it does not have many of the features common in other popular OO languages. Conversely, it also has many features that other popular OO languages do not.
As you have already discovered inheritance is managed via prototype objects, rather than by class inheritance. However, the prototype object is not examined when using the "instanceof" operator. This means that JavaScript does not support polymorphism. At least not out of the box.
You can find libraries that will make JavaScript conform to the model of OOP that you're used to; if you're under the gun this might be the best solution. (Although no library is ever going to make a JavaScript object polymorphic when examined using "instanceof"; an isInstanceOf function would probably be necessary.) Or you could choose another language which does conform to that model of OOP, but you're probably working in a browser, so that's obviously not an option. Or you could answer the question, "how can I solve my problem without polymorphism?"
You should note that the same question has been asked (by me). Check out the answers on that post.
You can use new or Object.create to achieve classical inheritance
function A(){
B.call(this);
}
function B(){
}
//there are 2 ways to make instanceof works
//1. use Object.create
A.prototype = Object.create(B.prototype);
//2. use new
//A.prototype = new B();
console.log(new A() instanceof B); //true
//make instanceof works
EmployerManager.prototype = Object.create(ProfileManager.prototype);
//add other prototype memebers
EmployerManager.prototype.superclass = ProfileManager;
console.log(new EmployerManager() instanceof ProfileManager); //true