In PHP , I've used traits before which is a nice way of separating out reusable code & generally making things more readable.
Here is a specific Example: ( trait and class can be in separate files ) . How could I do this in nodejs?
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
..more functions..
}
class TheWorld {
use HelloWorld;
}
$o = new TheWorldIsNotEnough();
$o->sayHello();
?>
In Nodejs , I have looked at at Stampit which looks quite popular , but surely there is a simple way to compose functions in a nice OOP & make more readable in nodejs without depending on a package?
Thanks for your time!
In JavaScript you can use any function as trait method
function sayHello() {
console.log("Hello " + this.me + "!");
}
class TheWorld {
constructor() {
this.me = 'world';
}
}
TheWorld.prototype.sayHello = sayHello;
var o = new TheWorld();
o.sayHello();
or pure prototype version
//trait
function sayHello() {
console.log("Hello " + this.me + "!");
}
function TheWorld() {
this.me = "world";
}
TheWorld.prototype.sayHello = sayHello;
var o = new TheWorld();
o.sayHello();
You can even create function that's apply traits to class
//trait object
var trait = {
sayHello: function () {
console.log("Hello " + this.me + "!");
},
sayBye: function () {
console.log("Bye " + this.me + "!");
}
};
function applyTrait(destClass, trait) {
Object.keys(trait).forEach(function (name) {
destClass.prototype[name] = trait[name];
});
}
function TheWorld() {
this.me = "world";
}
applyTrait(TheWorld, trait);
// or simply
Object.assign(TheWorld.prototype, trait);
var o = new TheWorld();
o.sayHello();
o.sayBye();
There is the NPM module: https://www.npmjs.com/package/traits.js
Code example from their README:
var EnumerableTrait = Trait({
each: Trait.required, // should be provided by the composite
map: function(fun) { var r = []; this.each(function (e) { r.push(fun(e)); }); return r; },
inject: function(init, accum) { var r = init; this.each(function (e) { r = accum(r,e); }); return r; },
...
});
function Range(from, to) {
return Trait.create(
Object.prototype,
Trait.compose(
EnumerableTrait,
Trait({
each: function(fun) { for (var i = from; i < to; i++) { fun(i); } }
})));
}
var r = Range(0,5);
r.inject(0,function(a,b){return a+b;}); // 10
Related
I'm trying to create a simple javascript inheritance but there's something I missed and I need your help.
Basically, I have a User which can have a username. I also have a Player which inherit from User and can have a score, and play.
var Game = (function () {
User = function () {
var username;
return {
setUsername: function (newUsername) {
username = newUserName;
},
getUsername: function () {
return username;
}
}
};
Player = function () {
var score = 0;
return {
getScore: function () {
return score;
},
play: function () {
score = Math.round(Math.random()*100);
}
};
};
Player.prototype = new User();
return {
player1: new Player(),
player2: new Player()
};
});
var game = new Game();
game.player1.setUsername('alex');
game.player2.setUsername('tony');
game.player1.play();
game.player2.play();
console.log(game.player1.getUsername()+': '+game.player1.getScore());
console.log(game.player2.getUsername()+': '+game.player2.getScore());
The issue I have comes from the fact I don't have access of the method from the User in my Player. I'm not sure how I can get access to them though.
Here is a jsfiddle: https://jsfiddle.net/3xsu8pdy/
Any idea?
Thanks.
Thanks.
First, note that you're using new with User and Person, but your code throws away the object new creates by returning a different object from those functions. So new User() and User() do exactly the same thing.
And that's largely the reason you don't have access to User features in Person, because the prototype of the object returned isn't User.prototype, it's Object.prototype.
If you don't want new...
...you want to create your "person" objects so they're backed by User directly (or via Object.create(User())):
var Game = (function() {
var User = function() { // <== Note the `var`
var username;
return {
setUsername: function(newUsername) {
username = newUserName;
},
getUsername: function() {
return username;
}
}
};
var Player = function() { // <== Note the `var`
var score = 0;
// Create the player, either using a User directly:
var player = User();
// ...or by using a User as a prototype:
var player = Object.create(User());
player.getScore = function() {
return score;
};
player.play = function() {
score = Math.round(Math.random() * 100);
};
return player;
};
return {
player1: Player(), // No `new`
player2: Player()
};
});
var game = new Game();
game.player1.setUsername('alex');
game.player2.setUsername('tony');
game.player1.play();
game.player2.play();
console.log(game.player1.getUsername() + ': ' + game.player1.getScore());
console.log(game.player2.getUsername() + ': ' + game.player2.getScore());
That keeps the username and score properties private, as in your original code.
If you want to use new
...then you probably want the fairly standard pattern I describe in this answer, which looks like this applied to your code:
var Game = (function() {
var User = function() {
};
User.prototype.setUsername = function(newUsername) {
this.username = newUserName;
};
User.prototype.getUsername = function() {
return this.username;
};
var Player = function() {
this.score = 0;
};
Player.prototype = Object.create(User.prototype);
Player.prototype.constructor = Player;
Player.prototype.getScore = function() {
return this.score;
};
Player.prototype.play = function() {
this.score = Math.round(Math.random() * 100);
};
return {
player1: new Player(),
player2: new Player()
};
});
var game = new Game();
game.player1.setUsername('alex');
game.player2.setUsername('tony');
game.player1.play();
game.player2.play();
console.log(game.player1.getUsername() + ': ' + game.player1.getScore());
console.log(game.player2.getUsername() + ': ' + game.player2.getScore());
Or in ES2015:
var Game = (function() {
class User {
setUsername(newUsername) {
this.username = newUserName;
}
getUsername() {
return this.username;
}
}
class Player extends User {
constructor() {
this.score = 0;
}
getScore() {
return this.score;
}
play() {
this.score = Math.round(Math.random() * 100);
}
}
return {
player1: new Player(),
player2: new Player()
};
});
var game = new Game();
game.player1.setUsername('alex');
game.player2.setUsername('tony');
game.player1.play();
game.player2.play();
console.log(game.player1.getUsername() + ': ' + game.player1.getScore());
console.log(game.player2.getUsername() + ': ' + game.player2.getScore());
Note that in both of those second two examples, username and score are no longer private. That said, even private variables in languages with built-in privacy like Java are trivially used outside of the private scope, via the reflection features of those languages.
In ES2015, we can use a WeakMap to get privacy as good as your original code's is:
var Game = (function() {
var UserNames = new WeakMap();
class User {
setUsername(newUsername) {
UserNames.set(this, newUsername);
}
getUsername() {
return UserNames.get(this);
}
}
var PlayerScores = new WeakMap();
class Player extends User {
constructor() {
PlayerScores.set(this, 0);
}
getScore() {
return PlayerScores.get(this);
}
play() {
PlayerScores.set(this, Math.round(Math.random() * 100));
}
}
return {
player1: new Player(),
player2: new Player()
};
});
var game = new Game();
game.player1.setUsername('alex');
game.player2.setUsername('tony');
game.player1.play();
game.player2.play();
console.log(game.player1.getUsername() + ': ' + game.player1.getScore());
console.log(game.player2.getUsername() + ': ' + game.player2.getScore());
That doesn't cause a memory leak, because when a User or Person object is no longer referenced by anything other than the WeakMap, the WeakMap lets go of it and it can be garbage collected.
I see where you are trying to go with the revealing module design pattern but If you are going for inheritance, you should be going with constructors. Something like:
var module = (function () {
function User () {
this.username = 'default';
}
User.prototype.setUsername = function (username) {
this.username = username;
};
User.prototype.getUsername = function () {
return this.username;
};
function Player () {
User.call(this);
this.score = 0;
}
Player.prototype = Object.create(User.prototype);
Player.prototype.getScore = function () {
return this.score;
};
Player.prototype.play = function () {
this.score = Math.round(Math.random()*100);
};
return {
player1 = new Player(),
player2 = new Player()
};
}());
So we are still using the revealing module pattern but we also get prototypal inheritance and all of the optimizations that come with it. This is what I would recommend.
Try this:
User = function () {};
User.prototype.setUsername = function (newUsername) {
this.username = newUserName;
};
User.prototype.getUsername = function () {
return this.username;
};
Same for Player :-)
The following code is a variation of this pattern. The extend() function takes care of binding prototypes together. The sup parameter refers to the parent prototype. Though, I'm afraid that it's old fashioned, I'm not sure if it's a good idea to go this way. Anyway, I believe that it's easier to understand than the previous code.
var A = extend(Object, function (sup) {
this.init = function (name) {
this.name = name;
};
this.whoami = function () {
return this.name;
};
});
var B = extend(A, function (sup) {
this.whoami = function () {
return 'I\'m ' + sup.whoami.call(this) + '.';
};
});
var C = extend(B, function (sup) {
this.init = function (name) {
sup.init.call(this, '☆ ' + name + ' ☆');
};
});
var a = new A('an instance of A');
var b = new B('an instance of B');
var c = new C('an instance of C');
log(
'a.whoami()',
'b.whoami()',
'c.whoami()',
'b instanceof A',
'b instanceof B',
'b instanceof C'
);
function extend (tail, head) {
function Class () {
this.init.apply(this, arguments);
}
head.prototype = tail.prototype;
Class.prototype = new head(tail.prototype);
Class.prototype.constructor = Class;
return Class;
}
<table><thead><tr><th>code</th><th>result</th></tr></thead><tbody></tbody></table><script>function log(){var el=document.getElementsByTagName('tbody')[0];Array.prototype.slice.call(arguments).forEach(function(x){el.innerHTML+='<tr><td>'+x+'</td><td>'+eval(x)+'</td></tr>';});}</script><style>table,td,th{text-align:left;border:1px solid #333;border-collapse:collapse;padding:.5em;}</style>
An example from some javascript course that I am following:
var Tornado = function(name, cities, degree) {
this.name = name;
this.cities = cities;
this.degree = degree;
};
Tornado.prototype = {
nCities: function() {
return this.cities.length
},
valueOf: function() {
return this.nCities() * this.degree;
},
toString: function() {
return this.cities[0][0].toString() + " " + this.name;
}
}
cities = [["Washington", 1], ["Rotterdam", 2]]
var x = new Tornado("crazy", cities, 3)
console.log(x.nCities())
console.log(x.valueOf())
console.log(x + 16)
console.log(x.toString() + "... wow!")
Object.prototype.findOwnerOfProperty = function(propName) {
var currentObject = this;
while(currentObject !== null) {
if(currentObject.hasOwnProperty(propName)) {
return currentObject;
} else {
currentObject = currentObject.__proto__;
}
}
return "No property found!";
};
console.log(x.findOwnerOfProperty("toString"));
The findOwnerOfProperty function returns the object where the property is defined. This is nice, but it would be nicer to also have the name of that object (Tornado.prototype in this example), how can I do that?
No built-in solution. but you can make a property
this._constructor = arguments.callee.name;
inside Tornado function and make a
getConstructor:function(){
return this._constructor;
}
inside prototype.
BTW , forgot to mention that you should remake
var Tornado = function
to:
function Tornado
function condition(){
this.expression = "";
this.toString = function(){
return this.expression;
}
};
function and(first, second){
this.expression = first + " and " + second;
}
function nop(){};
nop.prototype = condition.prototype;
and.prototype = new nop();
var a =new and(1,2);
console.log(a.toString());
it is expected to see "1 and 2" as output but this is what happened:
"[object Object]"
You are transfering the prototype of condition to nop's prototype. The problem is that your condition.toString is not declared in the prototype... Here:
function condition(){
this.expression = "";
};
condition.prototype.toString = function(){
return this.expression;
}
function and(first, second){
this.expression = first + " and " + second;
}
function nop(){};
nop.prototype = condition.prototype;
and.prototype = new nop();
var a =new and(1,2);
console.log(a.toString());
OR
function condition(){
this.expression = "";
this.toString = function(){
return this.expression;
}
};
function and(first, second){
this.expression = first + " and " + second;
}
function nop(){};
nop = condition;
and.prototype = new nop();
var a =new and(1,2);
console.log(a.toString());
you aren't overriding the toString method, because the constructer of condition is never called! try doing this;
condition.prototype.toString=function(){
return this.expression;
}
try passing strings into your and function, as at the moment you are trying to concatenate integers to a string var a =new and("1","2");
it should be like this
function condition(){
this.expression = "";
};
condition.prototype.toString = function(){
return this.expression;
}
Ok, so the problem here is you are mixing two inheritance patterns (http://davidshariff.com/blog/javascript-inheritance-patterns/) the pseudo-classical with the functional patterns.
You can create an object by adding methods on the constructor function:
function MyClass() {
var privateProperty = 1;
this.publicProperty = 2;
function pivateMethod() {
// some code ...
}
this.publicMethod = function() {
// some code ...
};
}
// inheritance
function SubClass() {
MyClass.call(this);
this.newMethod = function() { };
}
Here when you create a instance of this class you are creating every method again.
Then you have the prototype pattern:
function MyClass() {
this._protectedProperty = 1;
this.publicProperty = 2;
}
MyClass.prototype._protectedMethod = function() {
// some code ...
};
MyClass.prototype.publicMethod = function() {
// some code ...
};
// inheritance
function SubClass() {
MyClass.call(this);
}
SubClass.prototype = new MyClass();
SubClass.prototype.newMethod = function() { };
// OR
function SubClass() {
MyClass.call(this);
}
function dummy() { }
dummy.prototype = MyClass.prototype;
SubClass.prototype = new dummy();
SubClass.prototype.newMethod = function() { };
Yhen you must choose one of those two patterns, not both·
I've fixed your code on this fiddle: http://jsfiddle.net/dz6Ch/
Is there a small, lightweight solution for javascript class inheritance that will work well on both client and server side (node.js)? I'm not wanting a big library, just something that will allow me to declare a constructor and some methods, then have the ability for a class to inherit that.
John Resig outlines a simple inheritance framework in about 25 lines of code here. I have seen it used to good effect.
You can use it like this:
var Vehicle = Class.extend({
init: function(wheels) {
this.wheels = wheels;
}
});
var Truck = Vehicle.extend({
init: function(hp, wheels) {
this.horsepower = hp;
this._super(wheels);
},
printInfo: function() {
console.log('I am a truck and I have ' + this.horsepower + ' hp.');
}
});
var t = new Truck(4, 350);
t.printInfo();
take a look at https://github.com/ded/klass
I created this small library to use an ExtJs Style ClassManager. It's quite simple yet, but very flexible.
Install via node.js
npm install esf-core
Sample
Esf.define('A', {
a: null,
constructor: function (a) {
// Save var
this.a = a;
// Heyho
console.log('A');
},
foo: function (b) {
console.log('foo - ' + b);
}
});
Esf.define('B', {
b: null,
constructor: function (a, b) {
// Call super constructor
this.callParent(a);
// Save var
this.b = b;
// Heyho
console.log('B');
},
foo: function () {
this.callParent('bar');
}
}, {
extend: 'A'
});
// Use
var b = new B(1, 2);
// or
var b = Esf.create('B', 1, 2);
/*
* Output:
* A
* B
* foo - bar
*/
b.foo();
Repository
https://bitbucket.org/tehrengruber/esf-js-core
I've seen the prototype library used successfully.
I think this is much better than the init hax in the simple inheritance fw:
(function() {
var core = {
require : function(source) {
if ( typeof (source) != "object" || !source)
throw new TypeError("Object needed as source.");
for (var property in source)
if (source.hasOwnProperty(property) && !this.prototype.hasOwnProperty(property))
this.prototype[property] = source[property];
},
override : function(source) {
if ( typeof (source) != "object" || !source)
throw new TypeError("Object needed as source.");
for (var property in source)
if (source.hasOwnProperty(property))
this.prototype[property] = source[property];
},
extend : function(source) {
var superClass = this;
var newClass = source.hasOwnProperty("constructor") ? source.constructor : function() {
superClass.apply(this, arguments);
};
newClass.superClass = superClass;
var superClone = function() {
};
superClone.prototype = superClass.prototype;
newClass.prototype = new superClone();
newClass.prototype.constructor = newClass;
if (source)
newClass.override(source);
return newClass;
}
};
core.require.call(Function, core);
Function.create = function (source){
var newClass = source.hasOwnProperty("constructor") ? source.constructor : function() {};
newClass.override(source);
return newClass;
};
})();
The vehicle example with this:
var Vehicle = Function.create({
constructor : function(wheels) {
this.wheels = wheels;
}
});
var Truck = Vehicle.extend({
constructor : function(hp, wheels) {
this.horsepower = hp;
Vehicle.call(this, wheels);
},
printInfo : function() {
console.log('I am a truck and I have ' + this.horsepower + ' hp.');
}
});
var t = new Truck(4, 350);
t.printInfo();
I created a very lightweight library that works in-browser and in node.js. Its a super easy-to-use, bloatless library:
https://github.com/fresheneesz/proto
Example:
var Person = proto(function() { // prototype builder
this.init = function(legs, arms) { // constructor
this.legs = legs
this.arms = arms
}
this.getCaughtInBearTrap = function() { // instance method
this.legs -= 1
}
this.limbs = function() {
return this.arms + this.legs
}
})
var Girl = proto(Person, function() { // inheritance
this.haveBaby = function() {
return Person(2,2)
}
})
var g = Girl(2,2) // instantiation
g.getCaughtInBearTrap()
console.log("Girl has "+g.limbs()+" limbs")
console.log(": (")
I have something like this:
dog = function () {
this.age;
this.name;
this.dog1 = new dog.shepherd();
}
dog.prototype = {
bark : function () {
alert( (this.getName()) + " is barking." );
},
[3]**getName** : function () {
return this.name;
}
}
dog.shepherd = function () {
this.something;
}
dog.shepherd.prototype = function () {
guard : function () {
alert( ([2]**parent.getName()**) + " is barking." );
}
}
window.onload = function () {
var n = new dog();
[1]**n.guard()**;
}
How can I use a function which is prototyped to the dog from dog.speherd prototype?
In other words, when [1] is executed, then [2] is written in pseudo-code, to call [3].
I know this code shouldn't work; it's just to help me explain what I want.
Your title says you want to use composition, but your question body implies inheritance. Here's how you would do this with composition, which is probably the better option. A shepherd "is not a" dog after all (nor vice versa) so inheritance probably isn't right here.
Also, you usually don't want to set the entire prototype of a function like you're doing; just add the functions you want. And constructor functions by convention start with a capital letter.
function Shepherd(mydog) {
this.dog = mydog;
}
Shepherd.prototype.guard = function () {
alert( this.dog.getName() + " is barking." );
}
function Dog(age, name) {
this.age = age;
this.name = name;
}
Dog.prototype.getName = function () {
return this.name;
}
Dog.prototype.bark = function () {
alert(this.getName() + " is barking." );
}
window.onload = function () {
var someDog = new Dog(4, "Ubu");
var someShepherd = new Shepherd(someDog);
someShepherd.guard();
}
jsfiddle
I don't know why you need such code, but you can try this:
dog = function () {
this.age;
this.name;
this.dog1 = new dog.shepherd(this);
var d = this.dog1;
for (var i in dog.shepherd.prototype) {
this[i] = function(){
return this.dog1[i].apply(d, arguments);
}
}
}
dog.prototype = {
bark : function () {
alert( (this.getName()) + " is barking." );
},
getName : function () {
return this.name;
}
}
dog.shepherd = function (parent) {
this.parent = parent;
this.something;
}
dog.shepherd.prototype = {
guard : function () {
alert( (this.parent.getName()) + " is barking." );
}
}
window.onload = function () {
var n = new dog();
n.guard();
}