【问题标题】:Javascript objects: get parent [duplicate]Javascript对象:获取父级[重复]
【发布时间】:2011-02-28 04:11:39
【问题描述】:

我有以下(嵌套)对象:

obj: { subObj: { foo: 'hello world' } };

接下来我要做的就是像这样引用子对象:

var s = obj.subObj;

现在我想做的是从变量s 中获取对对象obj 的引用。 比如:

var o = s.parent;

这有可能吗?

【问题讨论】:

  • JavaScript 有很好的文档记录,参见例如ECMAScript specification 或阅读 JavaScript 之类的书。 David Flanagan 的权威指南。顺便说一句,没有 JSON 对象之类的东西:JSON 只是 JavaScript 对象的一种表示法。
  • 感谢您的链接。对不起 JSON,我只是把这个放进去,因为我正在研究一个与 JSON 相关的 sn-p - 我认为它可能是最有用的 (JSON) 来获取父对象。
  • obj.subObj 只是对象的引用。如果有可能得到Object的“父”,那将是一团糟,因为可以有多个指针指向同一个Object,它会返回多个父。
  • @JLRishe - 我今天刚刚遇到了一些事情,想由你运行它。我最初的 [现在已删除] 评论声称 字符串是字符串构造函数的实例,您称之为我的错误。但是,var my_string = "asdf"; my_string instanceof String; /* false */ my_string.constructor === String /* true */。你能解释一下吗?
  • @MarcelKorpel “顺便说一句,没有 JSON 对象这样的东西:JSON 只是 JavaScript 对象的一种表示法。” - 理论上可能不是,但实际上 JSON 对象是可序列化回 JSON 的 JS 对象。我认为将此类对象称为“JSON 对象”是合理的。

标签: javascript


【解决方案1】:

没有。无法知道它来自哪个对象。

sobj.subObj 都只是引用同一个对象。

你也可以这样做:

var obj = { subObj: {foo: 'hello world'} };
var obj2 = {};
obj2.subObj = obj.subObj;
var s = obj.subObj;

您现在拥有三个对同一对象的引用,obj.subObjobj2.subObjs。没有一个是特别的。

【讨论】:

    【解决方案2】:

    试试这个直到出现非否答案:

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

    【讨论】:

      【解决方案3】:

      对此有一个更“流畅”的解决方案:)

      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;
      

      【讨论】:

        【解决方案4】:

        另一个对象(父对象)内的嵌套对象(子对象)不能直接从其父对象获取数据。

        看看这个:

        var main = {
            name : "main object",
            child : {
                name : "child object"
            }
        };
        

        如果你问主对象它的子名称是什么 (main.child.name) 你会得到它。
        相反,您不能反之亦然,因为孩子不知道其父母是谁。
        (你可以得到main.name,但你不会得到main.child.parent.name)。

        顺便说一下,一个函数可能有助于解决这个问题。
        让我们扩展上面的代码:

        var main = {
            name : "main object",
            child : {
                name : "child object"
            },
            init : function() {
                this.child.parent = this;
                delete this.init;
                return this;
            }
        }.init();
        

        init 函数中,您可以简单地调用this 来获取父对象。
        所以我们直接在child 对象内定义parent 属性。
        然后(可选)我们可以删除init 方法。
        最后,我们将主对象作为init 函数的输出返回。

        如果您现在尝试获取main.child.parent.name,您将得到正确的结果。
        这有点棘手,但效果很好。

        【讨论】:

        • 这是否会在与大父母一起工作时产生任何性能问题,还是只是创建对单个对象的第二个引用?
        • @Josiah:性能问题不大。它只是创建了对父对象的第二个引用。
        • 这应该是公认的答案。
        • 这很聪明,正是我需要的。
        • deepCloning 和破坏应用程序时会无限下降。 main.child.parent.child.parent.child.parent.child.parent.child.parent...
        【解决方案5】:

        这是一个老问题,但是当我遇到它寻找答案时,我想我会添加我的答案以帮助其他人,一旦他们遇到同样的问题。

        我有这样的结构:

        var structure = {
            "root":{
                "name":"Main Level",
                nodes:{
                    "node1":{
                        "name":"Node 1"  
                    },
                    "node2":{
                        "name":"Node 2"  
                    },
                    "node3":{
                        "name":"Node 3"  
                    }
                }
            }
        }
        

        目前,通过引用其中一个子节点,我不知道如何获取名称值为“Main Level”的父节点。

        现在我介绍一个递归函数,它遍历结构并为每个节点对象添加一个父属性,并像这样用它的父对象填充它。

        var setParent = function(o){
             if(o.nodes != undefined){
                  for(n in o.nodes){
                      o.nodes[n].parent = o;
                      setParent(o.nodes[n]);
                  }
             }
        }
        

        然后我只需调用该函数,现在就可以在此对象树中获取当前节点的父节点。

        setParent(structure.root);
        

        如果我现在有对 root 的 seconds 子节点的引用,我可以调用。

        var node2 = structure.root.nodes["node2"];
        console.log(node2.parent.name);
        

        它会输出“Main Level”。

        希望这会有所帮助..

        【讨论】:

        • 这对我帮助很大!即使 JavaScript 本身不提供“父”属性,我们也可以在需要时手动添加。
        • @Nonlinearsound 当对象很大且嵌套层次多时性能如何?
        • 是的,我也这样做了。奇怪的是JS没有内置这个。
        • @MSC 并不奇怪。对于不使用或不想要的大型对象来说,这将是荒谬的开销,就像 Sajid 所询问的那样。
        • 我更喜欢这个,因为我不需要为所有孩子写东西:-)
        【解决方案6】:

        只是在子属性中保留父值

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

        【讨论】:

          【解决方案7】:

          要进一步迭代 Mik 的答案,您还可以递归地将父对象附加到所有嵌套对象。

          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

          【讨论】:

            【解决方案8】:

            你可以试试这个(这使用了一个构造函数,但我相信你可以稍微改变一下):

            function Obj() {
                this.subObj = {
                    // code
                }
                this.subObj.parent = this;
            }
            

            【讨论】:

            • 我使用了您的示例,但我只是在父级中创建了一个引用变量,并在需要时将其传递给需要它的子对象。谢谢。
            【解决方案9】:

            您将需要孩子来存储父母这个变量。由于 Parent 是唯一可以访问它的 this 变量的对象,因此它还需要一个函数将 this 变量放入 child 的 that 变量中,就像这样。

            var Parent = {
              Child : {
                that : {},
              },
              init : function(){
                this.Child.that = this;
              }
            }
            

            要对此进行测试,请尝试在 Firefox 的 Scratchpad 中运行它,它对我有用。

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

            【讨论】:

              【解决方案10】:

              当我加载一个 json 对象时,我通常通过像这样遍历对象数组来设置关系:

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

              然后你可以通过使用 .parent 来访问 somechildarray 中某个对象的父对象

              【讨论】:

                【解决方案11】:

                我一直在为我自己的宠物项目寻找当前对象的父对象的解决方案。在当前对象中添加对父对象的引用会在两个对象之间创建循环关系。

                考虑 -

                var obj = {
                    innerObj: {},
                    setParent: function(){
                        this.innerObj.parent = this;
                    }
                };
                obj.setParent();
                

                变量 obj 现在看起来像这样 -

                obj.innerObj.parent.innerObj.parent.innerObj...

                这不好。到目前为止,我发现的唯一解决方案是创建一个函数,该函数迭代最外层 Object 的所有属性,直到找到当前 Object 的匹配项,然后返回该 Object。

                例子-

                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
                

                当然,在不知道或没有对最外层对象的引用的情况下,没有办法做到这一点。这既不实用,也不是有效的解决方案。我会继续努力,希望能找到解决这个问题的好办法。

                【讨论】:

                  【解决方案12】:

                  这里的许多答案都涉及遍历一个对象并“手动”(尽管以编程方式)创建一个存储对父级的引用的父级属性。实现这一点的两种方式似乎是......

                  1. 在创建嵌套对象时使用init 函数进行循环,或者...
                  2. 将嵌套对象提供给填充父属性的函数

                  两种方法都有相同的问题...

                  随着嵌套对象的增长/变化,您如何维护父级?

                  如果我添加一个新的子子对象,它如何填充其父属性?如果您 (1) 使用 init 函数,则初始化已经完成并结束,因此您必须 (2) 将对象传递给函数以搜索新子代并添加适当的父属性。

                  只要对象/子对象为set,就使用 ES6 代理添加parent

                  下面的方法是为代理创建一个处理程序,每次设置对象时总是添加一个父属性。我将此处理程序称为parenter 处理程序。 parenter 的职责是识别何时设置对象,然后...

                  1. 使用适当的parentparenter 处理程序创建一个虚拟代理

                    var p = new Proxy({parent: target}, parenter);
                    
                  2. 复制提供的对象属性-- 因为您在此循环中设置代理属性,parenter 处理程序正在递归地工作;嵌套对象在每一层都有父对象

                    for(key in value){
                        p[key] = value[key];
                      }
                    
                  3. 设置代理而不是提供的对象

                    return target[prop] = p;
                    

                  完整代码

                  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"
                  

                  请注意,所有根子节点始终具有父属性,即使是稍后添加的子节点。

                  【讨论】:

                  • 太棒了!就我而言,这段代码有问题,因为我的项目使用“use strict”。为了解决这个问题,我只需在“set”函数的末尾添加“return true”
                  猜你喜欢
                  • 2013-06-24
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-11-12
                  • 2011-07-11
                  • 2013-07-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多