Does parent object know its children in JavaScript? - javascript

Let’s say we have:
var parent = {};
var child = Object.create(parent);
Can parent enumerate children and use their properties and methods somehow?
Yes, I can create an array of children. However, there’s a possibility to forget to do it with another new child.

Disregarding the unorthodox terminology, you can't enforce inheriting instances from adhering to anything and as a result there is no reliable way to do what you seek to do.
Try a Post-It ;-)

You will need some reference. An object does not know its parent automatically. But instead of saving an index, I think you can save the parent object itself. The parent is stored by reference, so if the parent is modified, the parent reference of the child reflects those changes. This is shown below in a slightly altered version of your code:
function parent() {
this.index = 0;
// Make children a property (for this test case) and
// pass 'this' (the parent itself) to a child's constructor.
this.children = [new child(this)];
}
function child(parent) {
// Store the parent reference.
this.parent = parent;
}
// Do this after the functions are declared. ;)
var parents = [new parent()];
// Set a property of the parent.
parents[0].test = "Hello";
// Read back the property through the parent property of a child.
alert(parents[0].children[0].parent.test); // Shows "Hello"

That is not a parent/child relationship.
That's a prototypal-inheritance link.
Prototypal inheritance is not the same.
const a = { x: 1, y: 2, doZ () { } };
const b = Object.create(a);
b.__proto__ === a; // true
The old-fashioned version of this was to do something like:
function A (x, y) {
this.x = x;
this.y = y;
}
A.prototype.doZ = function () { };
var a = new A(1, 2);
function B () { }
B.prototype = a;
var b = new B();
var c = new B();
var d = new B();
Should a be allowed to iterate over all instances of B?
Not really, no.

Related

How to implement classical class inheritance through prototypes

I would like to implement the following behavior in JS. Please note that the syntax is symbolic.
This is my parent class
class = TList {
FList: array;
function AddElement(Ele) {
Flist.Add(Ele)
};
function RemoveEle(Ele) {
FList.Remove(Ele)
};
}
Now I'm going to inherit from this class. My child class should automatically have all the properties of the parent and should be able to extend them without rewriting the code.
class = TAlertList(inherit from TList) {
function AddElement(Ele) {
Alert('element will be added');
call.parent.AddElement(Ele)
};
function RemoveElement(Ele) {
call.parent.RemoveElement(Ele);
Alert('element removed');
}
}
Please note how I inherit the parent methods at places I wish.
Now I should be able to create an object from my child class and do the following.
MyAlertList = new TAlertList;
MyAlertList.Add('hello');
console.log(MyAlertList.FList);
I should be able to inherit more child classes from TAlertList and be able to change the existing behavior. I need to do this in pure ES5 without using any libraries. Standard OOP practices are expected.
Please note that the TList constructor should be applied to the TAlertList instance;
ES5, first set up the base constructor
function TList() {
this.Flist = [];
// ...
}
TList.prototype = {
constructor: TList,
AddElement: function AddElement(Ele) {
this.Flist.push(Ele);
},
RemoveEle: function RemoveEle(Ele) {
var i = this.Flist.lastIndexOf(Ele);
if (i !== -1)
this.Flist.splice(i, 1);
}
};
Next set up the constructor which extends it, see how this means calling the base constructor on the instance being created by the extended constructor and creating a prototype object which inherits the prototype of the base constructor
function TAlertList() {
// construct from base
TList.call(this);
// further construct
// ...
}
TAlertList.prototype = Object.create(TList.prototype);
TAlertList.prototype.constructor = TAlertList;
// depending on how you want to reference stuff
TAlertList.prototype.AddElement = function AddElement(Ele) {
alert('element will be added');
TList.prototype.AddElement.call(this, Ele);
};
TAlertList.prototype.RemoveElement = function RemoveElement(Ele) {
TList.prototype.RemoveEle.call(this, Ele);
alert('element removed');
};
ES6 syntax makes use of the super keyword
class TList {
constructor() {
this.FList = [];
}
AddElement(Ele) {
this.Flist.push(Ele);
}
RemoveEle(Ele) {
var i = this.Flist.lastIndexOf(Ele);
if (i !== -1)
this.Flist.splice(i, 1);
}
}
class TAlertList extends TList {
constructor() {
super();
}
AddElement(Ele) {
alert('element will be added');
super.AddElement(Ele);
}
RemoveElement(Ele) {
super.RemoveEle(Ele);
alert('element removed');
}
}
Back to ES5, generalising as a factory so you can see a sort of algorithm of how to do it
function extend(baseConstructor, extendedConstructor, prototypeLayer) {
function Constructor() {
var i = 0, j = 0, args = Array.prototype.slice.call(arguments);
i = j, j += baseConstructor.length;
baseConstructor.apply(this, args.slice(i, j));
i = j, j = args.length;
extendedConstructor.apply(this, args.slice(i, j));
}
Object.defineProperty(Constructor, 'length', { // fix .length
value: baseConstructor.length + extendedConstructor.length,
configurable: true
});
Constructor.prototype = Object.create(baseConstructor.prototype);
Constructor.prototype.constructor = Constructor;
Object.assign(Constructor.prototype, prototypeLayer);
return Constructor;
}
So then
function Foo(x) {this.foo = x;}
Foo.prototype.fizz = 1;
var Bar = extend(Foo, function (x) {this.bar = x;}, {buzz: 1});
// ...
var b = new Bar('foo', 'bar');
b.foo; // "foo"
b.bar; // "bar"
b instanceof Foo; // true
b instanceof Bar; // true
b.fizz; // 1
b.buzz; // 1
Please note that this is an example of the algorithm you should be following when you write each extended constructor, not production code
Your code would be the following
function TList(){
this.FList = [];
}
TList.prototype.AddElement = function(Ele){
this.FList.push(Ele);
}
TList.prototype.RemoveElement = function(Ele){
this.FList.splice(Ele,1); //Ele is the index to remove;
}
This is an approximation to know how the inherit works in JavaScript.
function TAlertList (){
TList.call(this);
}
TAlertList.prototype = Object.create(TList.prototype);
TAlertList.prototype.constructor = TAlertList;
TAlertList.prototype.AddElement = function(ele){
alert('Element will be added');
TList.prototype.AddElement.call(this,ele);
};
TAlertList.prototype.RemoveElement = function(ele){
alert('Element will be remove');
TList.prototype.RemoveElement.call(this,ele);
};
So, the classic super call is
ParentClass.prototype.myMethod.call(this,args);
This is Q&A
Edit - Don't forget to read #paul's comment too if you planning to read the full text.
Almost all the answers came in were based on the popular "Person" example in the MDN documentation about JS OOP.
The theory behind this method is to put the fields of the object inside a constructor function while implementing the methods in a prototype object. A child object can inherit all the fields by calling the constructor function with a contrived this value. Also it can inherit all the methods by having the same prototype object of the parent as it's prototype object too. The only rule is that you need to call the methods using call or apply to point the methods to the correct this object when implementing inheritance.
I didn't like this approach for two reasons.
The fields and methods of an objects has to be separated between two objects (fields - constructor function, methods - prototype). This doesn't have the flavor of a unique behavior of a unique entity - which should be a single class.
You have to specify the name of the parent object when inheriting. This is not automatic. Let's say object C inherits from the object A. So, inside the methods of the object C, you need to mention object A when inheriting from it. (TList.prototype.AddElement.call(this, Ele);) What if object B comes in between later on? You will have to change all the inheriting methods of C to call from B. This is in no way near good inheritance.
I wanted to overcome these problems in MDN method. I came up with the following model with no this no call and no apply. Code is simple and easy to follow. You don't have to mention the name of the parent object when inheriting from it. So, a new class can come in between the parent and the child at any time without too many changes. Please discuss this and point out the weaknesses of this model.
Here is the function which returns the parent object.
function tList() {
var ret = Object.create(null);
ret.list = [];
ret.addElement = fucntion(ele) {
ret.list.push(ele)
};
return ret;
}
//You can create tList object like this:
var myList = tList();
myList.addElement('foo');
Now comes the child object:
function tAlertList() {
var ret = Object.create(tList());
//Lets inherit with the fashion of overriding a virtual method
ret.addElement = function(ele) {
//Here is new code
alert('Adding element ' + ele);
//Automatic inheritance now
Object.getPrototypeOf(ret).addElement(ele);
}
return ret;
}
//Just create the child object and use it
var myAlertList = tAlertList();
myAlertList.addElement('buzz') ;
You can have grand children object and inherit from parent without mentioning their names. Let's say you have to put tCustomList between tList and tAlertList. All you have to do is to tell the tAlertList to inherit from tCustomList in a single place. (var ret = Object.create(tCustomList());) Everything else remain the same.
Here is the fiddle.
With pure ES5, you could do it like this:
function TList() {
this.FList = []; //not really ideal.
}
TList.prototype.addElement = function(ele) {
this.FList.push(ele);
};
TList.prototype.removeElement = function(ele) {
this.FList.splice(this.FList.indexOf(ele), 1);
}
function TAlertList(){
this.FList = [];
}
TAlertList.prototype = new TList(); //inherit from TList
TAlertList.prototype.constructor = TAlertList; //reset constructor
TAlertList.prototype.addElement = function(ele) {
alert('element will be added');
TList.prototype.addElement.call(this, ele);
};
TAlertList.prototype.removeElement = function(ele) {
alert('element removed');
TList.prototype.removeElement.call(this, ele);
};
Couple of notes:
The FList property of its parent will actually be shared amongst all objects that inherit from the parent unless overwritten. That means that if you don't overwrite FList you'll get this:
var a = new TAlertList();
var b = new TAlertList();
a.push(1); //b.Flist === [1]
In my opinion, it would be best if you named your children functions with other names different from the parent. This way you don't need to do:
TList.prototype.function.call(this, parameter1, parameter2, ..);
You can just call them like this:
this.function(paremeter1, parameter2);
Of course, it's not a static way to call the parent as you can overwrite the function with your own. Then again TList.prototype.function isn't necessary the function of the parent of the object that owns the function. For that you'd need to use non-standard ES5 __proto__ property.
this.__proto__.function.call(this, parameter1, parameter2, ..);
Unless you plan on juggling the function around different objects, you don't need that.

Javascript: get parent object key name from within child [duplicate]

This question already has answers here:
access parent object in javascript
(15 answers)
Closed 5 years ago.
I have the following (nested) object:
obj: { subObj: { foo: 'hello world' } };
Next thing I do is to reference the subobject like this:
var s = obj.subObj;
Now what I would like to do is to get a reference to the object obj out of the variable s.
Something like:
var o = s.parent;
Is this somehow possible?
A nested object (child) inside another object (parent) cannot get data directly from its parent.
Have a look on this:
var main = {
name : "main object",
child : {
name : "child object"
}
};
If you ask the main object what its child name is (main.child.name) you will get it.
Instead you cannot do it vice versa because the child doesn't know who its parent is.
(You can get main.name but you won't get main.child.parent.name).
By the way, a function could be useful to solve this clue.
Let's extend the code above:
var main = {
name : "main object",
child : {
name : "child object"
},
init : function() {
this.child.parent = this;
delete this.init;
return this;
}
}.init();
Inside the init function you can get the parent object simply calling this.
So we define the parent property directly inside the child object.
Then (optionally) we can remove the init method.
Finally we give the main object back as output from the init function.
If you try to get main.child.parent.name now you will get it right.
It is a little bit tricky but it works fine.
No. There is no way of knowing which object it came from.
s and obj.subObj both simply have references to the same object.
You could also do:
var obj = { subObj: {foo: 'hello world'} };
var obj2 = {};
obj2.subObj = obj.subObj;
var s = obj.subObj;
You now have three references, obj.subObj, obj2.subObj, and s, to the same object. None of them is special.
This is an old question but as I came across it looking for an answer I thought I will add my answer to this to help others as soon as they got the same problem.
I have a structure like this:
var structure = {
"root":{
"name":"Main Level",
nodes:{
"node1":{
"name":"Node 1"
},
"node2":{
"name":"Node 2"
},
"node3":{
"name":"Node 3"
}
}
}
}
Currently, by referencing one of the sub nodes I don't know how to get the parent node with it's name value "Main Level".
Now I introduce a recursive function that travels the structure and adds a parent attribute to each node object and fills it with its parent like so.
var setParent = function(o){
if(o.nodes != undefined){
for(n in o.nodes){
o.nodes[n].parent = o;
setParent(o.nodes[n]);
}
}
}
Then I just call that function and can now get the parent of the current node in this object tree.
setParent(structure.root);
If I now have a reference to the seconds sub node of root, I can just call.
var node2 = structure.root.nodes["node2"];
console.log(node2.parent.name);
and it will output "Main Level".
Hope this helps..
Many of the answers here involve looping through an object and "manually" (albeit programmatically) creating a parent property that stores the reference to the parent. The two ways of implementing this seem to be...
Use an init function to loop through at the time the nested object is created, or...
Supply the nested object to a function that fills out the parent property
Both approaches have the same issue...
How do you maintain parents as the nested object grows/changes??
If I add a new sub-sub-object, how does it get its parent property filled? If you're (1) using an init function, the initialization is already done and over, so you'd have to (2) pass the object through a function to search for new children and add the appropriate parent property.
Using ES6 Proxy to add parent whenever an object/sub-object is set
The approach below is to create a handler for a proxy always adds a parent property each time an object is set. I've called this handler the parenter handler. The parenter responsibilities are to recognize when an object is being set and then to...
Create a dummy proxy with the appropriate parent and the parenter handler
var p = new Proxy({parent: target}, parenter);
Copy in the supplied objects properties-- Because you're setting the proxy properties in this loop the parenter handler is working recursively; nested objects are given parents at each level
for(key in value){
p[key] = value[key];
}
Set the proxy not the supplied object
return target[prop] = p;
Full code
var parenter = {
set: function(target, prop, value){
if(typeof value === "object"){
var p = new Proxy({parent: target}, parenter);
for(key in value){
p[key] = value[key];
}
return target[prop] = p;
}else{
target[prop] = value;
}
}
}
var root = new Proxy({}, parenter);
// some examples
root.child1 = {
color: "red",
value: 10,
otherObj: {
otherColor: "blue",
otherValue: 20
}
}
// parents exist/behave as expected
console.log(root.child1.color) // "red"
console.log(root.child1.otherObj.parent.color) // "red"
// new children automatically have correct parent
root.child2 = {color: "green", value3: 50};
console.log(root.child2.parent.child1.color) // "red"
// changes are detected throughout
root.child1.color = "yellow"
console.log(root.child2.parent.child1.color) // "yellow"
Notice that all root children always have parent properties, even children that are added later.
There is a more 'smooth' solution for this :)
var Foo = function(){
this.par = 3;
this.sub = new(function(t){ //using virtual function to create sub object and pass parent object via 't'
this.p = t;
this.subFunction = function(){
alert(this.p.par);
}
})(this);
}
var myObj = new Foo();
myObj.sub.subFunction() // will popup 3;
myObj.par = 5;
myObj.sub.subFunction() // will popup 5;
To further iterate on Mik's answer, you could also recursivey attach a parent to all nested objects.
var myApp = {
init: function() {
for (var i in this) {
if (typeof this[i] == 'object') {
this[i].init = this.init;
this[i].init();
this[i].parent = this;
}
}
return this;
},
obj1: {
obj2: {
notify: function() {
console.log(this.parent.parent.obj3.msg);
}
}
},
obj3: {
msg: 'Hello'
}
}.init();
myApp.obj1.obj2.notify();
http://jsbin.com/zupepelaciya/1/watch?js,console
You could try this(this uses a constructor, but I'm sure you can change it around a bit):
function Obj() {
this.subObj = {
// code
}
this.subObj.parent = this;
}
I have been working on a solution to finding the parent object of the current object for my own pet project. Adding a reference to the parent object within the current object creates a cyclic relationship between the two objects.
Consider -
var obj = {
innerObj: {},
setParent: function(){
this.innerObj.parent = this;
}
};
obj.setParent();
The variable obj will now look like this -
obj.innerObj.parent.innerObj.parent.innerObj...
This is not good. The only solution that I have found so far is to create a function which iterates over all the properties of the outermost Object until a match is found for the current Object and then that Object is returned.
Example -
var obj = {
innerObj: {
innerInnerObj: {}
}
};
var o = obj.innerObj.innerInnerObj,
found = false;
var getParent = function (currObj, parObj) {
for(var x in parObj){
if(parObj.hasOwnProperty(x)){
if(parObj[x] === currObj){
found = parObj;
}else if(typeof parObj[x] === 'object'){
getParent(currObj, parObj[x]);
}
}
}
return found;
};
var res = getParent(o, obj); // res = obj.innerObj
Of course, without knowing or having a reference to the outermost object, there is no way to do this. This is not a practical nor is it an efficient solution. I am going to continue to work on this and hopefully find a good answer for this problem.
Try this until a non-no answer appears:
function parent() {
this.child;
interestingProperty = "5";
...
}
function child() {
this.parent;
...
}
a = new parent();
a.child = new child();
a.child.parent = a; // this gives the child a reference to its parent
alert(a.interestingProperty+" === "+a.child.parent.interestingProperty);
You will need the child to store the parents this variable. As the Parent is the only object that has access to it's this variable it will also need a function that places the this variable into the child's that variable, something like this.
var Parent = {
Child : {
that : {},
},
init : function(){
this.Child.that = this;
}
}
To test this out try to run this in Firefox's Scratchpad, it worked for me.
var Parent = {
data : "Parent Data",
Child : {
that : {},
data : "Child Data",
display : function(){
console.log(this.data);
console.log(this.that.data);
}
},
init : function(){
this.Child.that = this;
}
}
Parent.init();
Parent.Child.display();
Just in keeping the parent value in child attribute
var Foo = function(){
this.val= 4;
this.test={};
this.test.val=6;
this.test.par=this;
}
var myObj = new Foo();
alert(myObj.val);
alert(myObj.test.val);
alert(myObj.test.par.val);
when I load in a json object I usually setup the relationships by iterating through the object arrays like this:
for (var i = 0; i < some.json.objectarray.length; i++) {
var p = some.json.objectarray[i];
for (var j = 0; j < p.somechildarray.length; j++) {
p.somechildarray[j].parent = p;
}
}
then you can access the parent object of some object in the somechildarray by using .parent

Javascript: initialize object by property

var someObject = function(arg) {
this.property = function() {
// do something with the argument
return arg;
}();
};
var obj = new someObject(some argument);
// object.property instanceof "someObject" should be true
When property of someObject is used, a new instance of newObject should be created. For example, when I use the native DOM Element's nextSibling property, a new DOM Element object instance is returned. I wonder if it is possible to create a similar structure. Or would such cause infinite recursion?
Strictly speaking, this is possible in ES5 (all latest browsers, yes that includes IE).
ES5 specifies getters and setters via the get and set keyword or the Object.defineProperty function so you can make functions behave like properties (think innerHTML). Here's how you can do it:
function Mother () {
this.name = '';
Object.defineproperty(this,'child',{
get: function(){
return new Mother();
}
});
}
So the object can now create new instances of itself simply by reading the child property:
var a = new Mother();
a.name = 'Alice';
b = a.child;
b.name = 'Susan';
alert(a.name) // Alice
alert(b.name) // Susan
a instanceof Mother; // true
b instanceof Mother; // true
Having said that, your observation about DOM elements is wrong. The DOM is simply a tree structure. You can create a similar structure yourself using old-school javascript:
function MyObject () {}
var a = new MyObject();
var b = new MyObject();
var c = new MyObject();
a.children = [b,c];
b.nextSibling = c;
c.prevSibling = b;
// now it works like the DOM:
b.nextSibling; // returns c
a.children[1]; // returns c
b.nextSibling.prevSibling instanceof MyObject; // true
No, that's not possible. You could set function to the property, but anyway, you will need to invoke function somehow (with property() notation or with call/apply), because function it's an object itself, and only () or call/apply say to interpreter that you want to execute code, but not only get access to function's object data.
Your understanding of the nextSibling property in the DOM is incorrect. It does not create a new DOMElement, it simply references an existing DOM Node.
When you create a sibling of an element to which you have a reference (e.g., via jQuery or document.createElement), the browser knows to update sibling and parent/child references.
So, the behavior you're trying to emulate doesn't even exist.
As others have intimated, simply accessing a property on an object is not sufficient to get the Javascript interpreter to "do" anything (other than deference the name you're looking up). You'll need property to be a function.
nextSibling doesn't return a new element, it returns an existing element which is the next sibling of the target element.
You can store an object reference as a property of another object just like you can store primitive values.
function SomeObject(obj) {
this.obj = obj;
}
var someObject = new SomeObject(new SomeObject());
someObject.obj instanceof SomeObject //true
However if you want to create a new instance of SomeObject dynamically when accessing someObject.obj or you want to return an existing object based on conditions that shoul be re-evaluated every time the property is accessed, you will need to use a function or an accessor.
function SomeObject(obj) {
this.obj = obj;
}
SomeObject.prototype.clone = function () {
//using this.constructor is a DRY way of accessing the current object constructor
//instead of writing new SomeObject(...)
return new this.constructor(this.obj);
};
var someObject = new SomeObject(new SomeObject());
var someObjectClone = someObject.clone();
Finally with accessors (be aware that they aren't cross-browser and cannot be shimmed)
function SequentialObj(num) {
this.num = num;
}
Object.defineProperty(SequentialObj.prototype, 'next', {
get: function () {
return new this.constructor(this.num + 1);
},
configurable: false
});
var seq = new SequentialObj(0);
console.log(seq.next); //SequentialObj {num: 1}
console.log(seq.next.next.next); //SequentialObj {num: 3}
If you want this.property() to return a new someObject you can write the class as follows:
var someObject = function(arg) {
this.arg = arg;
};
someObject.prototype.property = function(arg) {
// do something with the argument
return new someObject(arg||this.arg);
}();
var obj = new someObject(/*some argument*/);
// object.property instanceof "someObject" should be true
If you want it to return some already instantiated version you can write the code as follows:
var someObject = (function() {
var previous;
function(arg) {
this.arg = arg;
this.propertyBefore = previous;//refers to the someObject created before this one
if(previous) previous.property = this; //before.property now references this class
//this.property will be undefined until another instance of someObject is created
previous = this;
};
})()
var obj = new someObject(/*some argument*/);// returns someObject already created earlier (similar to nextSibling)
One small note - its best practice in javascript to declare class names with a capitalized name (SomeObject rather than someObject)

Working with JavaScript prototypes and accessing base class fields.

I am new to pseudo classes and prototypes in JavaScript and I am having a bit of difficulty implementing it properly. What I am trying to do is have a base 'class' with some fields then create a prototype of that base class with my methods defined as object literals. I am torn between doing it this way and just using singletons inside my base class for my methods. I think though that doing it this way is a little more elegant and I think I am actually not creating every method every time I create a new object.
Anyways, the small issue I am having is referencing the fields of my base class in my methods. Because when I try to reference them as this.field this is referring to the current function/ scope but I want it to reference the newly create object. Is there a work around for this or should I change the way I am creating my methods.
Below is some code that I think will make it more clear what I am doing and the problem I am having.
function BaseClass() {
this.items[];
this.fieldOne = "asdasd";
}
BaseClass.prototype = {
methodOne: function (input) {
function addElement(a. b) {
var element = {};
element.prop1 = a;
element.prop2 = b;
//The issue I am having is that items is undefined, how can I refernce the parent class object.
this.items.push(element);
}
function traverse() {
//go through a list and add a bunch of elements
addElement("ASdasd", 324);
}
},
methodTwo: function () {
//see now fieldOne is asdasd
console.log("fieldOne" + fieldOne);
}
}
var forTest = new BaseClass();
forTest.methodTwo();
So yeah I want to have some fields in the parent class that I can access from any method, but I would rather not just put the functions in my base class so that I do not create every method everytime I create a new object from BaseClass. Is there a work around or a better way to implement this?
Thanks in advance for the help.
You're losing the reference to this inside your nested functions. You can solve that with:
methodOne: function (input) {
var self = this;
function addElement(a. b) {
var element = {};
element.prop1 = a;
element.prop2 = b;
//The issue I am having is that items is undefined, how can I refernce the parent class object.
self.items.push(element);
}
function traverse() {
//go through a list and add a bunch of elements
addElement("ASdasd", 324);
}
// You never called anything?
// is traverse() what you wanted?
traverse();
},
methodOne: function (input) {
function addElement(a. b) {
var element = {};
element.prop1 = a;
element.prop2 = b;
//The issue I am having is that items is undefined, how can I refernce the parent class object.
this.items.push(element);
}
The issue here is that you've encountered javascript design error which is that this in subfunction is bound to wrong object. The ususal workaround for this looks like:
methodOne: function (input) {
var that = this;
function addElement(a, b) {
...
that.items.push(element);
}
}
In fact it's bound to the global object:
var o = {
f : function(){
var g = function(){
this.name = "test";
};
g();
}
};
o.f();
console.log(name); // "test"

Javascript objects: get parent [duplicate]

This question already has answers here:
access parent object in javascript
(15 answers)
Closed 5 years ago.
I have the following (nested) object:
obj: { subObj: { foo: 'hello world' } };
Next thing I do is to reference the subobject like this:
var s = obj.subObj;
Now what I would like to do is to get a reference to the object obj out of the variable s.
Something like:
var o = s.parent;
Is this somehow possible?
A nested object (child) inside another object (parent) cannot get data directly from its parent.
Have a look on this:
var main = {
name : "main object",
child : {
name : "child object"
}
};
If you ask the main object what its child name is (main.child.name) you will get it.
Instead you cannot do it vice versa because the child doesn't know who its parent is.
(You can get main.name but you won't get main.child.parent.name).
By the way, a function could be useful to solve this clue.
Let's extend the code above:
var main = {
name : "main object",
child : {
name : "child object"
},
init : function() {
this.child.parent = this;
delete this.init;
return this;
}
}.init();
Inside the init function you can get the parent object simply calling this.
So we define the parent property directly inside the child object.
Then (optionally) we can remove the init method.
Finally we give the main object back as output from the init function.
If you try to get main.child.parent.name now you will get it right.
It is a little bit tricky but it works fine.
No. There is no way of knowing which object it came from.
s and obj.subObj both simply have references to the same object.
You could also do:
var obj = { subObj: {foo: 'hello world'} };
var obj2 = {};
obj2.subObj = obj.subObj;
var s = obj.subObj;
You now have three references, obj.subObj, obj2.subObj, and s, to the same object. None of them is special.
This is an old question but as I came across it looking for an answer I thought I will add my answer to this to help others as soon as they got the same problem.
I have a structure like this:
var structure = {
"root":{
"name":"Main Level",
nodes:{
"node1":{
"name":"Node 1"
},
"node2":{
"name":"Node 2"
},
"node3":{
"name":"Node 3"
}
}
}
}
Currently, by referencing one of the sub nodes I don't know how to get the parent node with it's name value "Main Level".
Now I introduce a recursive function that travels the structure and adds a parent attribute to each node object and fills it with its parent like so.
var setParent = function(o){
if(o.nodes != undefined){
for(n in o.nodes){
o.nodes[n].parent = o;
setParent(o.nodes[n]);
}
}
}
Then I just call that function and can now get the parent of the current node in this object tree.
setParent(structure.root);
If I now have a reference to the seconds sub node of root, I can just call.
var node2 = structure.root.nodes["node2"];
console.log(node2.parent.name);
and it will output "Main Level".
Hope this helps..
Many of the answers here involve looping through an object and "manually" (albeit programmatically) creating a parent property that stores the reference to the parent. The two ways of implementing this seem to be...
Use an init function to loop through at the time the nested object is created, or...
Supply the nested object to a function that fills out the parent property
Both approaches have the same issue...
How do you maintain parents as the nested object grows/changes??
If I add a new sub-sub-object, how does it get its parent property filled? If you're (1) using an init function, the initialization is already done and over, so you'd have to (2) pass the object through a function to search for new children and add the appropriate parent property.
Using ES6 Proxy to add parent whenever an object/sub-object is set
The approach below is to create a handler for a proxy always adds a parent property each time an object is set. I've called this handler the parenter handler. The parenter responsibilities are to recognize when an object is being set and then to...
Create a dummy proxy with the appropriate parent and the parenter handler
var p = new Proxy({parent: target}, parenter);
Copy in the supplied objects properties-- Because you're setting the proxy properties in this loop the parenter handler is working recursively; nested objects are given parents at each level
for(key in value){
p[key] = value[key];
}
Set the proxy not the supplied object
return target[prop] = p;
Full code
var parenter = {
set: function(target, prop, value){
if(typeof value === "object"){
var p = new Proxy({parent: target}, parenter);
for(key in value){
p[key] = value[key];
}
return target[prop] = p;
}else{
target[prop] = value;
}
}
}
var root = new Proxy({}, parenter);
// some examples
root.child1 = {
color: "red",
value: 10,
otherObj: {
otherColor: "blue",
otherValue: 20
}
}
// parents exist/behave as expected
console.log(root.child1.color) // "red"
console.log(root.child1.otherObj.parent.color) // "red"
// new children automatically have correct parent
root.child2 = {color: "green", value3: 50};
console.log(root.child2.parent.child1.color) // "red"
// changes are detected throughout
root.child1.color = "yellow"
console.log(root.child2.parent.child1.color) // "yellow"
Notice that all root children always have parent properties, even children that are added later.
There is a more 'smooth' solution for this :)
var Foo = function(){
this.par = 3;
this.sub = new(function(t){ //using virtual function to create sub object and pass parent object via 't'
this.p = t;
this.subFunction = function(){
alert(this.p.par);
}
})(this);
}
var myObj = new Foo();
myObj.sub.subFunction() // will popup 3;
myObj.par = 5;
myObj.sub.subFunction() // will popup 5;
To further iterate on Mik's answer, you could also recursivey attach a parent to all nested objects.
var myApp = {
init: function() {
for (var i in this) {
if (typeof this[i] == 'object') {
this[i].init = this.init;
this[i].init();
this[i].parent = this;
}
}
return this;
},
obj1: {
obj2: {
notify: function() {
console.log(this.parent.parent.obj3.msg);
}
}
},
obj3: {
msg: 'Hello'
}
}.init();
myApp.obj1.obj2.notify();
http://jsbin.com/zupepelaciya/1/watch?js,console
You could try this(this uses a constructor, but I'm sure you can change it around a bit):
function Obj() {
this.subObj = {
// code
}
this.subObj.parent = this;
}
I have been working on a solution to finding the parent object of the current object for my own pet project. Adding a reference to the parent object within the current object creates a cyclic relationship between the two objects.
Consider -
var obj = {
innerObj: {},
setParent: function(){
this.innerObj.parent = this;
}
};
obj.setParent();
The variable obj will now look like this -
obj.innerObj.parent.innerObj.parent.innerObj...
This is not good. The only solution that I have found so far is to create a function which iterates over all the properties of the outermost Object until a match is found for the current Object and then that Object is returned.
Example -
var obj = {
innerObj: {
innerInnerObj: {}
}
};
var o = obj.innerObj.innerInnerObj,
found = false;
var getParent = function (currObj, parObj) {
for(var x in parObj){
if(parObj.hasOwnProperty(x)){
if(parObj[x] === currObj){
found = parObj;
}else if(typeof parObj[x] === 'object'){
getParent(currObj, parObj[x]);
}
}
}
return found;
};
var res = getParent(o, obj); // res = obj.innerObj
Of course, without knowing or having a reference to the outermost object, there is no way to do this. This is not a practical nor is it an efficient solution. I am going to continue to work on this and hopefully find a good answer for this problem.
Try this until a non-no answer appears:
function parent() {
this.child;
interestingProperty = "5";
...
}
function child() {
this.parent;
...
}
a = new parent();
a.child = new child();
a.child.parent = a; // this gives the child a reference to its parent
alert(a.interestingProperty+" === "+a.child.parent.interestingProperty);
You will need the child to store the parents this variable. As the Parent is the only object that has access to it's this variable it will also need a function that places the this variable into the child's that variable, something like this.
var Parent = {
Child : {
that : {},
},
init : function(){
this.Child.that = this;
}
}
To test this out try to run this in Firefox's Scratchpad, it worked for me.
var Parent = {
data : "Parent Data",
Child : {
that : {},
data : "Child Data",
display : function(){
console.log(this.data);
console.log(this.that.data);
}
},
init : function(){
this.Child.that = this;
}
}
Parent.init();
Parent.Child.display();
Just in keeping the parent value in child attribute
var Foo = function(){
this.val= 4;
this.test={};
this.test.val=6;
this.test.par=this;
}
var myObj = new Foo();
alert(myObj.val);
alert(myObj.test.val);
alert(myObj.test.par.val);
when I load in a json object I usually setup the relationships by iterating through the object arrays like this:
for (var i = 0; i < some.json.objectarray.length; i++) {
var p = some.json.objectarray[i];
for (var j = 0; j < p.somechildarray.length; j++) {
p.somechildarray[j].parent = p;
}
}
then you can access the parent object of some object in the somechildarray by using .parent

Categories