68
    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() { }
        }
    }
1

16 Answers 16

70

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();
Sign up to request clarification or add additional context in comments.

Comments

41
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();

1 Comment

This is a more accurate answer rather than one accepted. The accepted answer just wipe out the question but this is one is answering it. Thank you
7

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

1 Comment

If you wrap this.showGreetings in an object it won't work.
4

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

Comments

4

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 ?

Comments

4

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

Comments

4

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

Comments

2

David Dorward's right here. The easiest solution, tho, would be to access user.Name, since user is effectively a singleton.

Comments

1

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

Comments

0

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"

Comments

0

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

Comments

0

I was looking for a solution to this problem today. For my use case, this is how I solved it.

 var parentObject = {
    title: "My object",
    nestedArrayOfMoreObjects: [
        {nestedObj1: "this is object 1",
        getParentObj: function() {
            this.parentObj = parentObject;
        }
    },
        {nestedObj2: "this is object 2",
            getParentObj: function() {
                this.parentObj = parentObject;
            }
        },
            {nestedObj3: "this is object 3",
                getParentObj: function() {
                    this.parentObj = parentObject;
                }
            }]
        }

This worked for me because I wanted to create a new array of ONLY some of the array items from each of my "parent objects", based on some conditions (in my code there are a few different parent objects with different names and properties!). Then I wanted to be able to link all of the items in my new array back to their respective parents, and the other properties of those parents.

So I created a function to perform the addParents() method to each of the objects in my new array (console logs are just to check it works..)

function addParents() {
            newArray.forEach(
                (item) => {
                    item.getParentObj();
                    console.log(item.parentObj);
                    console.log(item.parentObj.title);
                }
            )
        }

        addParents(); 

So once that function has run, I can then use any of the parent object properties on the items in my new array:

newArray[0].parentObj.title 

and this would get "My Object" - because this was the title of the parent object associated with this child object.

This is a bit convoluted, but this is a solution I found to access the parent object and its properties!

Comments

-1

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

Comments

-2
// 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();

Comments

-2

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

Comments

-2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.