Not sharing object properties in OLOO inheritance - javascript

I'm not sure on the best approach to have object properties that are individual for each object in a OLOO inheritance chain.
Check this fiddle or consider the following code:
http://jsfiddle.net/HB7LU/19413/
Parent = {
array: [],
add: function(element) {
this.array.push(element + this.array.length.toString());
return this;
},
getAll: function() {
return this.array;
}
};
Child = Object.create(Parent, {
removeAllButOne: { value: function() {
this.array.splice(1);
return this;
}}
});
foo = Object.create(Parent);
foo.add('foo');
bar = Object.create(Child);
bar.add('bar');
In the fiddle a click on the foo or bar text will call the foo.add(...) or bar.add(...) function to add an element to the objects array, resulting in one extra <p> tag in the output.
The result is not what I want. Both foo and bar share the same array. But its easy to understand what happens, if we look up the object inheritance we can see the following:
Ok then, what can I do go get around this? There were two options that came to my mind:
Option 1)
http://jsfiddle.net/HB7LU/19419/
Parent = function() {
return {
array: [],
add: function(element) {
this.array.push(element + this.array.length.toString());
return this;
},
getAll: function() {
return this.array;
}
};
};
Child = Object.create(Parent(), {
removeAllButOne: { value: function() {
this.array.splice(1);
return this;
}}
});
foo = Object.create(Parent());
foo.add('foo');
bar = Object.create(Child);
bar.add('bar');
This would create a new Parent object, creating all the functions of the Parent object each time a Parent object is created or a child "inherits" from a (new) Parent object. While this solves the problem I had, it seems like a bad idea to always recreate the same functions over and over again for each child type object.
Option 2)
http://jsfiddle.net/HB7LU/19420/
Parent = Object.create({
add: function(element) {
this.array.push(element + this.array.length.toString());
return this;
},
getAll: function() {
return this.array;
}
}, {
ctor: { value: function(someArgs) {
this.array = [];
// maybe use someArgs
return this;
}}
});
Child = Object.create(Parent, {
removeAllButOne: { value: function() {
this.array.splice(1);
return this;
}}
});
foo = Object.create(Parent).ctor();
foo.add('foo');
bar = Object.create(Child).ctor();
bar.add('bar');
This seems to also solve the problem but avoids the recreation of the Parent object and its functions. So is this the way to go? What if I had multiple children in the inheritance chain that also have private properties?
Something like this?
Child = Object.create(Parent, {
ctor: { value: function(someArgs) {
this.__proto__.ctor(someArgs);
this.otherPrivate = {};
// maybe use someArgs
return this;
}},
removeAllButOne: { value: function() {
this.array.splice(1);
return this;
}}
});
Children would be shadowing the parent ctor with their own function... but in their ctor function they could call the parents ctor to not break functionality.
Thoughts and advice is highly appreciated, thanks!

Easiest way is to use Constructors so array is always created as an own property on the instance
// define Parent
function Parent() {
this.array = []; // array will be an instance property
}
Parent.prototype = {}; // inherit all the goodies from Object.prototype
Object.assign(Parent.prototype, { // using `Object.assign` for shorthand
add: function (element) {
this.array.push(element + this.array.length.toString());
return this;
},
getAll: function () {
return this.array;
}
});
// define Child
function Child() {
Parent.apply(this); // apply Parent constructor to the instance
}
Child.prototype = Object.create(Parent.prototype); // inherit Parent's prototype chain
Object.assign(Child.prototype, {
removeAllButOne: function () {
this.array.splice(1);
return this;
}
});
Now have
var a = new Child(),
b = new Child();
a.array === b.array; // false
You could also write this using ES 6's classes, but that is just syntactic sugar for what I've written above and will result in the same structures.

OLOO favours composition over inheritance. You could use a factory method pattern with Object.assign to compose objects with simple prototype delegation:
// Composable prototype objects, or "traits"
var base = {
add: function(element) {
this.array.push(element + this.array.length.toString());
return this;
},
getAll: function() {
return this.array;
}
};
var canRemoveAllButOne = {
removeAllButOne: function() {
this.array.splice(1);
return this;
}
}
// Factory functions
// You could think of these like external constructors
function createBase() {
return Object.assign({}, base, {
array: []
})
}
function createComposed() {
var base = createBase();
return Object.assign(base, canRemoveAllButOne)
}
// Test
function log(s) {
document.write(s + "<br>");
}
var b1 = createBase();
var b2 = createBase();
var c1 = createComposed();
var c2 = createComposed();
b1.add(1);
b1.add(2);
b2.add(9);
c1.add('a');
c2.add('b');
log(b1.getAll());
log(b2.getAll());
log(c1.getAll());
log(c2.getAll());

Related

Can I navigate upwards through a javascript object in the same way I can through the DOM? [duplicate]

var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
},
GetUserName: function() { }
}
}
You can't.
There is no upwards relationship in JavaScript.
Take for example:
var foo = {
bar: [1,2,3]
}
var baz = {};
baz.bar = foo.bar;
The single array object now has two "parents".
What you could do is something like:
var User = function User(name) {
this.name = name;
};
User.prototype = {};
User.prototype.ShowGreetings = function () {
alert(this.name);
};
var user = new User('For Example');
user.ShowGreetings();
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
alert(this.Parent.Name); // "this" is the Methods object
},
GetUserName: function() { }
},
Init: function() {
this.Methods.Parent = this; // it allows the Methods object to know who its Parent is
delete this.Init; // if you don't need the Init method anymore after the you instanced the object you can remove it
return this; // it gives back the object itself to instance it
}
}.Init();
Crockford:
"A privileged method is able to access the private variables and
methods, and is itself accessible to the public methods and the
outside"
For example:
function user(name) {
var username = name;
this.showGreetings = function()
{
alert(username);
}
}
You can try another approach using a closure:
function userFn(name){
return {
Methods: {
ShowGreetings: function() {
alert(name);
}
}
}
}
var user = new userFn('some user');
user.Methods.ShowGreetings();
Old question but why can't you just do something like this :
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
var thisName = user.Name; //<<<<<<<<<
},
GetUserName: function() { }
}
}
Because you will only call user.Methods.ShowGreetings() after the user has been instantiated. So you will know about the variable 'user' when you want to use its name ?
As others have said, with a plain object it is not possible to lookup a parent from a nested child.
However, it is possible if you employ recursive ES6 Proxies as helpers.
I've written a library called ObservableSlim that, among other things, allows you to traverse up from a child object to the parent.
Here's a simple example (jsFiddle demo):
var test = {"hello":{"foo":{"bar":"world"}}};
var proxy = ObservableSlim.create(test, true, function() { return false });
function traverseUp(childObj) {
console.log(JSON.stringify(childObj.__getParent())); // returns test.hello: {"foo":{"bar":"world"}}
console.log(childObj.__getParent(2)); // attempts to traverse up two levels, returns undefined because test.hello does not have a parent object
};
traverseUp(proxy.hello.foo);
Very late to the party, but this works
var user = {
Name: "Some user",
Methods() {
return {
that: this,
ShowGreetings: function() {
console.log(this.that.Name)
},
GetUserName: function() { }
}
}
}
user.Methods().ShowGreetings() // Some user
David Dorward's right here. The easiest solution, tho, would be to access user.Name, since user is effectively a singleton.
ES6 Classes
One simple solution would be to create a Class with methods!
class User {
// Assign properties when an instance
// is created using the `new` keyword
constructor(name) {
this.name = name;
}
// Methods:
showGreetings() {
console.log(`Hello, ${this.name}!`);
}
getUserName() {
return this.name;
}
// Or rather, use Getters:
get username() {
return this.name;
}
}
// Create a new user:
const user = new User("Praveen");
// Use methods:
user.showGreetings(); // "Hello, Praveen!"
console.log(user.getUserName()); // "Praveen"
console.log(user.username); // "Praveen"
Why the above suggestion? Mostly because:
you cannot reference a parent Object from a child Object directly
const User = {
name: "Some user", // hardcoded stuff? Is this an intentional Singleton?
methods: { // <<< Child Object of User
sayName() {
// Sadly, `this` refers to `methods`, not to `user`:
console.log(this); // methods{}
console.log(User.name); // "Some user" // Get Singleton's name
// ... but that's not what you want.
}
}
};
User.methods.sayName();
// ^^^^^^^ Why would you want this `methods` anyways?!
and it makes no sense to hardcode Strings (like "Some user") inside an Object Singleton — which could actually be a reusable function Object.
If you want to associate a child Node to a parent Node — read this answer (Get value of parent Object).
How about this way?
user.Methods.ShowGreetings.call(user, args);
So you can access user.Name in ShowGreetings
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function(arg) {
console.log(arg, this.Name);
},
GetUserName: function() { }
},
Init: function() {
this.Methods.ShowGreetings.call(this, 1);
}
};
user.Init(); // => 1 "Some user"
As a variant:
var user = (obj => {
Object.keys(obj.Methods).map(option => {
const currOpt = obj.Methods[option];
if (currOpt instanceof Function) {
obj.Methods[option] = currOpt.bind(obj);
};
});
return obj;
})({
Name: "Some user",
Methods: {
Greeting: function () { return this.Name },
GetUserName: function() { console.log(this) }
},
});
But I don't know why somebody can use this strange approach
I know I'm very late.
I wrote this simple method. Let's say you have:
{
subObj: {
x:'hello_world';
}
}
Then, if you want a reference to the bigger object from subObj, you can convert it to a function, and utilize this.
var tmpVal=reference_to_subObj; //keep value of subObj safe
reference_to_subObj=function(){return this;}//this returns the scope, here the parent
var parent=reference_to_subObj(); //call the function
reference_to_subObj=tmpVal; delete tmpVal; //set things back to normal
//Now you have variable 'parent'.
I used a Function() constructor because it let me create the function as a string, so I could pass a string as code.
function findParent(stringReference) {
Function(/*same as above, except filled in all reference_to_subObj with stringReference.*/
//stringReference is a stringified version of dot or bracket notation.
So I could call findParent('obj.subObj').
// Make user global
window.user = {
name: "Some user",
methods: {
showGreetings: function () {
window.alert("Hello " + this.getUserName());
},
getUserName: function () {
return this.getParent().name;
}
}
};
// Add some JavaScript magic
(function () {
var makeClass = function (className) {
createClass.call(this, className);
for (key in this[className]) {
if (typeof this[className][key] === "object") {
makeClass.call(this[className], key);
}
}
}
var createClass = function (className) {
// private
var _parent = this;
var _namespace = className;
// public
this[className] = this[className] || {};
this[className].getType = function () {
var o = this,
ret = "";
while (typeof o.getParent === "function") {
ret = o.getNamespace() + (ret.length === 0 ? "" : ".") + ret;
o = o.getParent();
}
return ret;
};
this[className].getParent = function () {
return _parent;
};
this[className].getNamespace = function () {
return _namespace;
}
};
makeClass.call(window, "user");
})();
user.methods.showGreetings();
I ran across this old post trying to remember how to solve the problem. Here is the solution I used. This is derived from Pro JavaScript Design Patterns by Harmes and Diaz (Apress 2008) on page 8. You need to declare a function and then create a new instance of it as shown below. Notice the Store method can access "this".
function Test() {
this.x = 1;
}
Test.prototype = {
Store: function (y) { this.x = y; },
}
var t1 = new Test();
var t2 = new Test();
t1.Store(3);
t2.Store(5);
console.log(t1);
console.log(t2);
Like #Quentin said, there is no upwards relationship in JS. However try this workaround;
foo = { bar: {parent: foo} };
console.log(foo);
console.log(foo.bar.parent);
which is also similar to;
function Foo(){
this.bar = {parent: this}
}
foo = new Foo();
console.log(foo);
console.log(foo.bar.parent);

Javascript/Node.js: ES5 child class instance accessing parent class method

I am trying to access parent's method in child's constructor as following:
file1.js
var ParentClass = function(arg) {
this.arg = arg;
this.result = {};
};
ParentClass.prototype = {
constructor: ParentClass,
isActive: function(condition) {
return new Date(condition.valid).getTime() <= Date.now())
}
};
module.exports = ParentClass;
file2.js
var ParentClass = require('file1');
var ChildClass= function(arg) {
ParentClass.apply(this, arguments);
this.init();
};
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass;
ChildClass.prototype = {
init: function() {
this.result = this.arg.validity
.filter(function(elem) {
return this.isActive(elem)
}.bind(this));
}
}
module.exports = ChildClass;
file3.js
var ChildClass= require('file2.js');
var instance = new ChildClass(param);
initializing such instance gives me
TypeError: this.isActive is not a function
at Object.<anonymous> (file2.js)
at Array.filter (native)
at Object.ChildClass.init (file2.js)
Help and explanation appreciated. Thank you!
You have two separate assignments to ChildClass.prototype. One will override the other. Instead, you need to first initialize your prototype with Object.create() as you are doing and then you need to ADD new methods to it, not assign to the whole prototype, thus replacing everything you just put there.
These are the two conflicting statements:
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype = {...};
One common way to fix this is to use Object.assign() to copy your methods onto the existing prototype:
Object.assign(ChildClass.prototype, {
init: function() {
this.result = this.arg.validity
.filter(function(elem) {
return this.isActive(elem)
}.bind(this));
}
});
This will copy each of your methods over to the already existing prototype object and this method is more commonly used when you have lots of methods.
You can also just assign the new methods one at a time (more commonly used when you have just a few methods):
ChildClass.prototype.init = function() {
this.result = this.arg.validity.filter(function(elem) {
return this.isActive(elem)
}.bind(this));
}
You are redefining ChildClass.prototype as a new object, which overwrites your assignment using Object.create() a few lines prior. Instead, simply define the init method on it.
Try this:
var ParentClass = function(arg) {
this.arg = arg;
this.result = {};
};
ParentClass.prototype = {
constructor: ParentClass,
isActive: function(condition) {
return new Date(condition.valid).getTime() <= Date.now();
}
};
var ChildClass = function(arg) {
ParentClass.apply(this, arguments);
this.init();
};
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass;
ChildClass.prototype.init = function() {
this.result = this.arg.validity
.filter(function(elem) {
return this.isActive(elem);
}.bind(this));
};
var instance = new ChildClass({
validity: [{
valid: "01/01/17"
}]
});
console.log(instance);

Simpler JavaScript inheritance without duplicate code

I am always struggling with the JavaScript object/class inheritance thing. I also don't like the duplicate code in all the examples I can find (the name of the object needs to be written a few times).
As far as I understand, proper inheritance in JavaScript looks like this:
function Parent(v) {
console.log('Parent', v);
}
Parent.prototype.helloParent = function() {
console.log('hello parent');
}
function Child(v) {
Parent.call( this, 'from child');
console.log('Child');
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.helloChild = function() {
console.log('hello child');
}
c = new Child();
console.log(c instanceof Child);
c.helloParent();
c.helloChild();
In this example, to extend the "Parent" object, I have to write "Child" four times, "Parent" two times. I want to type them both just once once – because of DRY.
I also don't want to define a custom function for this inheritance stuff. That just feels odd for me, to need a user function for such a fundamental functionality (and it is getting hard to read unknown code, because you never know what this specific inheritance function is doing exactly).
So I tried to find a simpler version. However I am not sure if I missed something?
function Parent(v) {
console.log('Parent', v);
this.helloParent = function() {
console.log('hello parent');
}
}
(Child = function(v) {
this.constructor('from child');
console.log('Child');
this.helloChild = function() {
console.log('hello child');
}
}).prototype = Parent.prototype;
c = new Child();
console.log(c instanceof Child);
c.helloParent();
c.helloChild();
Is this okay or does it have serious drawbacks?
Edit: Regarding the comments, sadly it seems that it has some serious drawback. Are there any other solutions to reduce at least to write the name of the parent object multiple times?
I use two very small functions for simplifying inheritance in JavaScript:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function extend(constructor, keys) {
var prototype = Object.create(constructor.prototype);
for (var key in keys) prototype[key] = keys[key];
return defclass(prototype);
}
It is used as follows:
var Parent = defclass({
constructor: function (a) {
console.log("Parent", a);
},
helloParent: function () {
console.log("helloParent");
}
});
var Child = extend(Parent, {
constructor: function () {
Parent.call(this, "fromChild");
console.log("Child");
},
helloChild: function () {
console.log("helloChild");
}
});
Finally:
var child = new Child;
console.log(child instanceof Child);
child.helloParent();
child.helloChild();
Putting it all together:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function extend(constructor, keys) {
var prototype = Object.create(constructor.prototype);
for (var key in keys) prototype[key] = keys[key];
return defclass(prototype);
}
var Parent = defclass({
constructor: function (a) {
console.log("Parent", a);
},
helloParent: function () {
console.log("helloParent");
}
});
var Child = extend(Parent, {
constructor: function () {
Parent.call(this, "fromChild");
console.log("Child");
},
helloChild: function () {
console.log("helloChild");
}
});
var child = new Child;
console.log(child instanceof Child);
child.helloParent();
child.helloChild();
Hope that helps.
oop in javascript is ugly. (at least until ES6 which supports the class and implements keywords) but even ES6 will not support multiple inheritance. I wrote a small class library (available on github) for javascript that makes creating classes and inheritance much easier to both develop and maintain. for example to create a class just do this:
ds.make.class({
type: 'a',
constructor: function (x) { this.val = x; },
mul: function (s) {
this.val *= s;
return this;
}
});
// now to inherit class a just do this...
ds.make.class({
type: 'b',
inherits: a,
constructor: function (x) { this.val = x; },
sub: function (s) {
this.val -= s;
return this;
}
});
var o = new b(5);
var output = o.mul(3).sub(5).val; // output = 10

javascript's different extend methods

What is the difference between extend methods in JavaScript?
Let's say we have the following classes:
var BaseClass = function() {
this.class_name = 'BaseClass';
this.foo = function() {
return 'foo';
}
this.sub = {
moreStuff: 'weeee'
}
};
BaseClass.prototype.bar = function () {
return 'To be or not to be';
}
var SubClass = function() {
this.class_name = 'SubClass';
this.bar = function() {
return 'bar';
}
this.sub = {
moreStuff: 'wooohooo'
}
};
Method A:
SubClass.prototype = new BaseClass();
SubClass.prototype.constructor = SubClass;
Method B (from underscore.js):
_.extend = function(obj) {
each(slice.call(arguments, 1), function(source) {
if (source) {
for (var prop in source) {
obj[prop] = source[prop];
}
}
});
return obj;
};
Method C (from LiveScript):
function extend$(sub, sup){
function fun(){}
fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
Method A looks simpler. Why go through the trouble of copying the object, one property at a time?
Yes, Method A looks simpler but using it you can inherit only from one object. What if you want your SubClass to inherit from BaseClassOther as well. In this case you should go for the Method B ( to inherit from BaseClassOther as well).
You can not do
SubClass.prototype = new BaseClassOther();
again this will overwrite prototype property.
Please have a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
In Method A, in other circumstances, BaseClass() might be written to require an argument and to fail if it does not receive a valid one. The other two methods are not bothered by this. Perhaps the inherited constructors you are working with are not bothered by this either.

Unable to access members in javascript

I'm defining a class in javascript as
Class = (function() {
var privateFunction = function() { return "private"; }
return { publicFunction: function() { return privateFunction("public"); } };
)();
Here user can access Class.publicFunction, but not Class.privateFunction.
Now I want to provide the user an interface to extend this Class. So I added a public function extend.
Class = (function() {
var privateFunction = function() { return "private"; }
return {
publicFunction: function() { return privateFunction("public"); }
extend: function(source) {
dest=this;
for(var prop in source)dest[prop] = source[prop]
}
};
)();
My aim was to use the extend attribute as follows
Class.extend({
someFunc: function() { return privateFunction("hooray"); }
});
and access it as
Class.someFunc()
The problem I face is the call to the privateFunction() in the extended function someFunc is not available for it. I can understand that it is the problem of the scope, but, is there anyway to solve my need.
While it's a horrible violation of encapsulation, you could do what you describe by passing the function you want to add as a string and evaling it in extend:
Class.extend({
someFunc: 'function() { return privateFunction("hooray"); }'
});
and in the extend function, change
for(var prop in source)dest[prop] = source[prop]
to
for(var prop in source)dest[prop] = eval(source[prop])
this.before = function(){return "public"};
this.publicFucntion = function(){privateFunction(this.before());}
Then just override this.before.

Categories