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);
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);
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
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.
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.