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();
}
Related
I was looking for good example of Javascript prototypical inheritance on SO and this question, Benefits of using 'Object.create' for inheritance, has an excellent answer and so I tried to push my luck by adding another object type to the prototype chain and I found something that looks strange.
The original listing has Dog inheriting from Animal and we can see Animal in the prototype chain. However, if we add Creature and have Animal inheriting from that then Animal disappears from the reported prototype chain if we use console.info.
Can anyone explain why the prototype chain shouldn't say Dog->Animal->Creature ?
Here is code listing
"use strict";
//https://www.typescriptlang.org/docs/handbook/classes.html
var Creature = (function () {
function Creature() {
return this;
}
Creature.prototype.deadOrAlive = function () {
console.log("alive"); //hard code for now
}
return Creature;
}());
var Animal = (function () {
Animal.prototype = Object.create(Creature.prototype);
function Animal() {
return this;
}
Animal.prototype.move = function (distanceInMeters) {
if (distanceInMeters === void 0) {
distanceInMeters = 0;
}
console.log("Animal moved " + distanceInMeters + "m.");
};
return Animal;
}());
var Dog = (function () {
/* https://stackoverflow.com/questions/17392857/benefits-of-using-object-create-for-inheritance/17393153#answer-17393153 */
Dog.prototype = Object.create(Animal.prototype);
function Dog() {
return this;
}
Dog.prototype.bark = function () {
console.log("Woof! Woof!");
};
return Dog;
}());
var dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
dog.deadOrAlive();
//debugger;
A colleague at a Javascript boot camp of which I am member has come up with a one-line solution, just use Object.setPrototypeOf( Animal.prototype, Creature.prototype ). Thanks, Ray!
//https://www.typescriptlang.org/docs/handbook/classes.html
"use strict";
var Creature = (function () {
function Creature() {
return this;
}
Creature.prototype.deadOrAlive = function () {
console.log("alive"); //hard code for now
}
return Creature;
}());
var Animal = (function () {
Object.setPrototypeOf( Animal.prototype, Creature.prototype )
function Animal() {
return this;
}
Animal.prototype.move = function (distanceInMeters) {
if (distanceInMeters === void 0) {
distanceInMeters = 0;
}
console.log("Animal moved " + distanceInMeters + "m.");
};
return Animal;
}());
var Dog = (function () {
/* https://stackoverflow.com/questions/17392857/benefits-of-using-object-create-for-inheritance/17393153#answer-17393153 */
Object.setPrototypeOf( Dog.prototype, Animal.prototype )
function Dog() {
return this;
}
Dog.prototype.bark = function () {
console.log("Woof! Woof!");
};
return Dog;
}());
var dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
dog.deadOrAlive();
//debugger;
This example works as expected:
class A {
constructor(name) {
this.name = name
}
}
A.prototype.someMethod1 = function() { console.log("1: " + this.name) }
A.prototype.someMethod2 = function() { console.log("2: " + this.name) }
let a = new A("John")
a.someMethod1()
a.someMethod2()
Sometimes we need methods to be grouped by it's meaning into child objects, to call it like: a.some.method1(), a.some.method2(). Let's try to write:
class A {
constructor(name) {
this.name = name
}
}
A.prototype.some = {
method1: function() { console.log("1: " + this.name) },
method2: function() { console.log("2: " + this.name) }
}
Now we able to call a.some.method1() and a.some.method2(), but "this" inside of it points to "a.some" and not to "a" as desired. So, "this.name" inside these metods now will be "undefined".
So can I bind context of methods to main object?
Currently I know only one method to do that. Something like this in constructor:
class A {
constructor(name) {
this._name = name
// bind context to this
Object.keys(this.name).forEach(n => {
this.name[n] = this.name[n].bind(this)
})
}
}
But are there more elegant methods?
Note: it should be specified at the declaration time. Modifications of method calls like a.some.method1().call(a) are not acceptable.
This may not be at all what you're looking for, but you could consider doing something like this:
class A {
constructor(name) {
this.name = name;
this.some = new Some(this);
}
}
class Some {
constructor(a) {
this.a = a;
}
method1() { console.log("1: " + this.a.name) }
method2() { console.log("2: " + this.a.name) }
}
var x = new A('x name');
x.some.method1();
x.some.method2();
Yes it's possible you can define the instance of class and then add method on prototype by binding it to a
class A {
constructor(name) {
this.name = name
}
}
let a = new A("Hello")
A.prototype.some = {
method1: function() { console.log("1: " + this.name) }.bind(a),
method2: function() { console.log("2: " + this.name) }.bind(a)
}
a.some.method1()
You could make some a function that returns a object where you can specify what methods to have and then you can call those methods from that object.
class A {
constructor(name) {
this.name = name
}
}
A.prototype.someMethod1 = function() {
console.log("1: " + this.name)
}
A.prototype.someMethod2 = function() {
console.log("2: " + this.name)
}
A.prototype.some = function() {
return {
someMethod1: this.someMethod1.bind(this),
someMethod2: this.someMethod2.bind(this)
}
}
let a = new A("John")
a.someMethod1()
a.someMethod2()
a.some().someMethod1()
a.some().someMethod2()
The same logic can be implemented with class methods without prototype. You can also omit the bind with arrow functions as class properties but you should care about support in this case.
class A {
constructor(name) {
this.name = name
}
some1 = () => `1. ${this.name}`
some2 = () => `2. ${this.name}`
some = () => {
return {
some1: this.some1,
some2: this.some2
}
}
}
let a = new A("John")
console.log(a.some1())
console.log(a.some2())
console.log(a.some().some1())
console.log(a.some().some2())
You can also use getter for some so you can call it like property instead of method.
class A {
constructor(name) {
this.name = name
}
some1 = () => `1. ${this.name}`
some2 = () => `2. ${this.name}`
get some() {
return {
some1: this.some1,
some2: this.some2
}
}
}
let a = new A("John")
console.log(a.some1())
console.log(a.some2())
console.log(a.some.some1())
console.log(a.some.some2())
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
Prior to using ES6 we could instantiate a "class" like so...
var Animal = function(){}
and then...
var dog = new Animal()
the context within the "class" will be the class (instance) itself
var Animal = function( name ){
this.name = name;
this.getName = function(){
// the context here (this) is the class (Animal)
return this.name; // works well
}
}
The question is, if I wouldn't want to pollute the root scope and use sub-objects, for various uses, then the context would become the object in which the function is being kept
var Animal = function( name ){
this.utilities = {
this.getName : function(){
// the context here is the 'utilities' object so...
return this.name // wouldn't work
}
}
}
of course we could always use something in the form of
dog.utilities.getName.call(dog)
but this would be kind of long and uncomfortable...
is there a way to create the 'utilities' object and apply the context to all of its functions to point back to the root scope? without having to use call and apply every time? (an answer without using ES6 would be great...)
One way to ensure that this is what you want it to be in the various utilities functions is to use arrow functions for them, since arrow functions close over the this where they're defined:
class Animal {
constructor(name) {
this.name = name;
this.utilities = {
getName: () => { // This is an arrow function
return this.name; //
} //
};
}
}
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
This is basically the ES2015+ version of the old var t = this; solution:
function Animal(name) {
var t = this;
this.name = name;
this.utilities = {
getName() {
return t.name;
}
};
}
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
In both cases, this means that you're creating new function objects for each individual instance of Animal (the code will be shared between those objects, but the objects are distinct). That's fine unless there are going to be a lot of Animal instances.
Alternately, you could have a helper that you pass the instance to:
const Animal = (function() {
class Utilities {
constructor(animal) {
this.a = animal;
}
getName() {
return this.a.name;
}
}
class Animal {
constructor(name) {
this.name = name;
this.utilities = new Utilities(this);
}
}
return Animal;
})();
const dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
or
var Animal = (function() {
function Utilities(animal) {
this.a = animal;
}
Utilities.prototype.getName = function getName() {
return this.a.name;
};
return function Animal(name) {
this.name = name;
this.utilities = new Utilities(this);
}
})();
var dog = new Animal("dog");
console.log(dog.utilities.getName()); // "dog"
...which lets utilities reuse its function objects via Utilities.prototype.
You could probably use the following:
var utilities = function (context) {
return {
getName: function () {
console.log(context.name)
}
}
}
var Animal = function( name ){
this.name = name
this.utilities = utilities.call(null, this)
}
var dog = new Animal('dog')
dog.utilities.getName()
But, if you are okay doing this: dog.getName() instead of dog.utilities.getName() then you might have a cleaner solution (IMO) as follows:
var Animal = function( name ){
this.name = name
}
var utilities = {
getName: function () {
console.log(this.name)
}
};
Object.assign(Animal.prototype, utilities)
var dog = new Animal('dog')
dog.getName()
Let me know if that works. Thanks.
NEW ANSWER:
var UTILITIES = {
getName: function () {
console.log(this.self.name)
}
}
var Animal = function (name) {
this.name = name
this.utilities = Object.create(UTILITIES, {
self: {
value: this
}
})
}
var dog = new Animal('dog')
dog.utilities.getName()
Variation includes the use of a 'self' attribute which points to the instance of interest. Now, this could look more intuitive.
You can use getter methods. I find them very useful for cases where I need formatted value. This way, the utilities/ logic is only known to this class and is not exposed outside.
function Person(fname, lname) {
var _fname = fname;
var _lname = lname;
Object.defineProperty(this, 'fullName', {
get: function(){
return _fname + ' ' + _lname
}
});
Object.defineProperty(this, 'firstName', {
get: function(){
return _fname
},
set: function(value) {
_fname = value;
}
});
Object.defineProperty(this, 'lastName', {
get: function(){
return _lname
},
set: function(value) {
_lname = value;
}
});
}
var person = new Person('hello', 'world');
console.log(person.fullName);
person.firstName = 'Hello';
console.log(person.fullName);
person.lastName = 'World'
console.log(person.fullName);
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/