简体   繁体   中英

access parent object in javascript

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

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.

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 ?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM