Rewrite javascript function into node.js module - javascript

I have this function: (which is I guess abstract factory for creating javascript objects)
var $class = function(definition) {
var constructor = definition.constructor;
var parent = definition.Extends;
if (parent) {
var F = function() { };
constructor._superClass = F.prototype = parent.prototype;
constructor.prototype = new F();
}
for (var key in definition) {
constructor.prototype[key] = definition[key];
}
constructor.prototype.constructor = constructor;
return constructor;
};
A use it for defining classes C/java syntax like with polymorphism and extending:
var Bullet = $class({
Extends: GameObject,
constructor: function(texturePath, x, y, ctx, direction, passable, player) {
GameObject.call(this, texturePath, x, y, ctx, 1, 1, passable, new Array(8, 8, 0, 0));
},
isActive: function() {
},
getPlayer: function() {
},
update: function(dt) {
},
destroy: function() {
},
processCollision: function() {
}
});
And then calling:
var bullet = new Bullet(params);
I tried to rewrite it into nodejs module like this:
(function(){
var $class = function(definition) {
var constructor = definition.constructor;
var parent = definition.Extends;
if (parent) {
var F = function() { };
constructor._superClass = F.prototype = parent.prototype;
constructor.prototype = new F();
}
for (var key in definition) {
constructor.prototype[key] = definition[key];
}
constructor.prototype.constructor = constructor;
return constructor;
};
module.exports.createClass = function() {
return $class();
}
});
And then call it with:
var c = require(__dirname + "\\Class");
var Bullet = c.createClass({
Extends: GameObject,
constructor: function() {}
});
But it doesn't work, can you please help me with rewriting?
UPDATE: I rewrited it from #Salem answer, but I lost extending and polymorphism in process.
In order to have extending I simply have to write instead of
Extends: ParentClass
this:
Extends: ParentClass.constructor
I've expected that polymorphism would be something like:
// in class which is extended from ParentClass
ParentClass.method();
// in parent class adding line
module.exports.method = ParentClass.method;
But this is undefined. So where is the catch?
FINALLY I used mochiscript module for nodejs, it is even better syntax sugar with more object oriented functionality.

In your code, createClass is a function without any parameter. Also you call $class without any paramter also.
You don't need to wrap all your code in a function, because everything you declare there won't be accessible from outside unless you export it. So it should be something like this:
var func = function(definition) {
var constructor = definition.constructor;
var parent = definition.Extends;
if (parent) {
var F = function() { };
constructor._superClass = F.prototype = parent.prototype;
constructor.prototype = new F();
}
for (var key in definition) {
constructor.prototype[key] = definition[key];
}
constructor.prototype.constructor = constructor;
return constructor;
};
module.exports.createClass = func;
This means that if you require this module as X, the only thing you can access is X.createClass, and not X.func or anything else.

Related

How to inherit variables in JavaScript?

function Singer(g) {
this.genre = g;
this.rock = function() {
console.log("ROCK");
}
}
Singer.prototype.sing = function() {
console.log(this.genre);
}
function metalSinger() {
}
metalSinger.prototype = Singer.prototype
var james = new metalSinger();
console.log(james.sing())
The metalSinger object only inherits the prototype function of object Singer. How can I inherit the variables of Singer (this.genre) and also the function (this.rock) ?
You can use the class pattern with inheritance.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
function Singer(g) {
this.genre = g;
this.rock = function() {
console.log("ROCK");
}
}
Singer.prototype.sing = function() {
console.log(this.genre);
}
function MetalSinger(g) {
Singer.call(this, g);
}
var ms = new MetalSinger("foo");
console.log(ms.rock());
One way you can achieve this is by calling the parent constructor function inside the child constructor like this:
function Singer(g) {
this.genre = g;
this.rock = function() {
console.log("ROCK");
}
}
Singer.prototype.sing = function() {
console.log(this.genre);
}
function metalSinger() {
Singer.call(this, 'metal');
}
metalSinger.prototype = Object.create(Singer.prototype);
var james = new metalSinger();
james.sing();
This way before constructing the child object, parent constructor will be called first to initialise the object.
How can I inherit the variables of Singer (this.genre) and also the function (this.rock) ?
Basically like this:
Singer.call(this, genre);
By doing so, you first call Singer in context of metalSinger which adds its (Singer's) properties to this object of metalSinger. Also it is better to create new object through Object.create() and put all the functions in Prototype.
function Singer(g) {
this.genre = g;
}
Singer.prototype.sing = function() {
console.log(this.genre);
}
Singer.prototype.rock = function() {
console.log("ROCK");
}
function metalSinger(g) {
Singer.call(this, g);
}
metalSinger.prototype = Object.create(Singer.prototype);
var james = new metalSinger("metal");
james.sing(); // "metal"
james.rock(); // "ROCK"

Convert global function into static utility in javascript

I have a Shape class, it's defined in the global scope:
function Shape(t) {
this.type;
Shape.prototype.init = function(){
this.type = t;
//more work here
}
this.init();
}
I want to consolidate all global functions/classes into a single class to avoid conflicts with global namespace
function Util(){}
Util.Shape = function(){...}
Util.Point = function(){...}
That works, but I don't like repeating Util. each time, so I use a property like a namespace for related functions, in this case, math:
Util.math = {
Shape: function(t) {
this.type;
Shape.prototype.init = function(){
this.type = t;
//more work here
}
this.init();
},
Point: function(t) {...}
}
But that doesn't work; complains about this.init(); makes sense since Shape.prototype is not needed here, so it's removed:
Util.math = {
Shape: function(t) {
this.type;
this.init = function(){
this.type = t;
}
this.init();
}
}
Works now:
var square = new Util.math.Shape('square');
var circle = new Util.math.Shape('circle');
console.log(square.type); // 'square'
console.log(circle.type); // 'circle'
Questions:
Any issue with this approach? More effective/cleaner way to do it?
Also, why does this not work? (this is coolness)
Util.math = {
Shape: function(t) {
this.type;
this.init = function(){
this.type = t;
}
}.init(); //<------coolness
}
You can also do:
var myLib = (function() {
var obj = {};
function Shape(t) {
this.init(t);
}
Shape.prototype.init = function(t){
this.type = t;
}
obj.Shape = Shape;
// more stuff
return obj;
}());
var shape = new myLib.Shape('circle');
console.log(shape.type); // circle
Assuming that the init thing is just an example.

Maximum call stack size exceeded in javascript

I write a extend method to achieve inheritance in javascript:
function Class() {}
Class.prototype.create = function () {
var instance = new this();
instance.init();
return instance;
}
// extend method
Class.extend = Class.prototype.extend = function (props) {
var SubClass = function () {};
SubClass.prototype = Object.create(this.prototype);
for (var name in props) {
SubClass.prototype[name] = props[name];
}
SubClass.prototype.constructor = SubClass;
if (this.prototype.init) {
SubClass.prototype.callSuper = this.prototype.init;
}
SubClass.extend = SubClass.prototype.extend;
SubClass.create = SubClass.prototype.create;
return SubClass;
}
// level 1 inheritance
var Human = Class.extend({
init: function () {
}
});
// level 2 inheritance
var Man = Human.extend({
init: function () {
this.callSuper();
}
})
// level 3 inheritance
var American = Man.extend({
init: function () {
this.callSuper();
}
})
// initilization
American.create();
Then the develop tool report Maximum call stack size exceeded
I think the callSuper method cause the problem, callSuper call init, and init call callSuper, both with the same context.
But I don't know how to fixed it!
Can anyone could help me? How to set the correct context?
You have a scope problem. Here is the solution:
function Class() {}
Class.prototype.create = function () {
var instance = new this();
instance.init();
return instance;
}
// extend method
Class.extend = Class.prototype.extend = function (props) {
var SubClass = function () {},
self = this;
SubClass.prototype = Object.create(this.prototype);
for (var name in props) {
SubClass.prototype[name] = props[name];
}
SubClass.prototype.constructor = SubClass;
if (this.prototype.init) {
SubClass.prototype.callSuper = function() {
self.prototype.init();
}
}
SubClass.extend = SubClass.prototype.extend;
SubClass.create = SubClass.prototype.create;
return SubClass;
}
// level 1 inheritance
var Human = Class.extend({
init: function () {
console.log("Human");
}
});
// level 2 inheritance
var Man = Human.extend({
init: function () {
console.log("Man");
this.callSuper();
}
})
// level 3 inheritance
var American = Man.extend({
init: function () {
console.log("American");
this.callSuper();
}
})
// initilization
American.create();
The key moment is to wrap init method in a closure:
SubClass.prototype.callSuper = function() {
self.prototype.init();
}
Here is a jsfiddle containing the solution http://jsfiddle.net/krasimir/vGHUg/6/

Inheriting a class that has the same constructor but different/similar prototypes

Suppose I have a constructor:
function Constructor(input) {
this.input = input
}
Constructor.prototype.method = function() {
console.log('a')
}
But I want to make another class using a copy of the constructor, but changing the prototypes.
function Constructor2(input) {
this.input = input
}
Constructor2.prototype.method = function() {
console.log('b')
}
I don't want to redefine the constructor. How would you do this? Ideally it would be something as simple as:
var Constructor2 = inherits(Constructor)
Constructor2.prototype.method = // overwrite the inherited `method()`
var inherits = function(childCtor, parentCtor) {
/** #constructor */
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
/** #override */
childCtor.prototype.constructor = childCtor;
};
// How to use it:
var Constructor1 = function() {
//add all your methods, variables etc
};
Constructor1.prototype.myMethod = function() {
};
var Contructor2 = function() {
Contructor1.call(this); // Call the super class constructor
};
inherits(Contstructor2, Constructor1);
// Constructor2 now inherits from Constructor1
// override, add methods variables etc, whatever you need.
// Have fun!
Okay, much easier just to use apply:
function newConstructor(Super) {
function Construct() {
Super.apply(this, arguments)
}
require('util').inherits(Construct, Super)
return Construct
}
Here's a nasty-ish solution:
function Constructor1(input) {
this.input = input;
}
Constructor1.prototype.method = function() {
console.log('a');
}
// be careful here: evals the string value of Constructor1 with references to "Constructor1" changed to "Constructor2"
eval(Constructor1.toString().replace("Constructor1", "Constructor2"));
Constructor2.prototype.method = function() {
console.log('b');
}
var c1 = new Constructor1(1);
var c2 = new Constructor2(2);
console.log(c1.constructor === c2.constructor) // true
c1.method() // a
c2.method() // b

Javascript prototype and issues accessing class

Family = function(name) {
this._Name = name;
}
Family.prototype = {
getName: function() {
return this._Name;
},
People: function(num) {
this._Number = num;
}
}
Family.People.prototype = {
clearNumber: function() {
this._Number = 0;
}
}
People is a nested class. Its parent class is Family.
I get the error that Family.People is undefined. Could someone correct the code above?
Working code
// function doesn't need "new" operator
var Family = function(name) { this._Name = name; };
Family.prototype = {
getName: function() { return this._Name; }, // missing comma
People: function(num) {
this._Number = num;
}
};
// work with prototypes
Family.prototype.People.prototype = {
clearNumber: function() { this._Number = 0; }
};
This will work. But you have to be aware, that when you call:
var f = new Family("Doe");
f.People is just an object constructor, and not an instance of some other object. You will have to instantiate it as well like:
f.members = new f.People(3);
Sou you have a constructor within your instance which is rather confusing.
A better approach
So it would probably be better if you'd write your prototypes this way:
var Family = function(name) {
this._Name = name;
this.getName = function() { return this._Name; };
};
Family.People = function(num) {
this._Number = num;
this.clearNumber = function() { this._Number = 0; };
};
This actually makes a class within a class (and not within instances). So upper lines would be called this way:
var f = new Family("Doe");
f.members = new Family.People(3);
Drill down of f instance would look like:
f
_Name
getName()
members
_Number
clearNumber()
Private variables
var Family = function(name) {
var _name = name;
this.getName = function() { return _name; };
};
Family.People = function(num) {
var _num = num;
this.getNumber = function() { return _num; }
this.clearNumber = function() { _num = 0; };
};
This way we make variables private and only accessible within so they can't be manipulated outside. You must always use functions to manipulate them. This makes it more robust especially when there are certain business rules related to variable values.
var f = new Family("Doe");
f._name; // this is undefined because "_name" is private closure variable
Drill down of f instance would now look more like a class object instance:
f
getName()
members
getNumber()
clearNumber()
Notice that you are assigning to Family.prototype.People then trying to access Family.People.
Family is not an instance of Family thus it does not have the properties of that class - Family is an instance of Function thus you are trying to access Function.prototype.People in that 3rd statement. (this is a bit of a simplification)
i.e. what you want to be doing is
Family.prototype.People.prototype = {
clearNumber:function(){this._Number = 0;}
}
You are also missing a comma before people, but I assume this is a typo...
You should declare the People constructor as a key in the Family object:
Family.People = function(num) {
this._Number = num;
}
The Family prototype will be in the prototype chain for new objects of type Family; not a part of Family itself.

Categories

Resources