开发者

access parent object in javascript

开发者 https://www.devze.com 2022-12-12 14:46 出处:网络
var user = { Name: \"Some user\", Methods: { ShowGreetings: function() { // at this point i want to access v开发者_如何学JAVAariable \"Name\",
    var user = {
        Name: "Some user",
        Methods: {
            ShowGreetings: function() {
                    // at this point i want to access v开发者_如何学JAVAariable "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);
0

精彩评论

暂无评论...
验证码 换一张
取 消