【问题标题】:In JavaScript, how do you get to the 'this' object of the outer object, from a method of an object that's an element of an array in the outer object在 JavaScript 中,如何从作为外部对象中数组元素的对象的方法获取外部对象的“this”对象
【发布时间】:2014-06-18 04:31:28
【问题描述】:

我有一个这样创建的 JavaScript 对象:

var outer = {
    list: [
        {
            field1: 111,
            field2: 222,
            doSomething: function() {
                var x =id;
            }
        },
        {
            field1: 333,
            field2: 444,
            doSomething: function() {
                var x =id;
            }
        } 
    ],

    id: 0,
};

假设调用列表第一个元素的doSomething()。 在 doSomething() 内部,我可以访问 this.field1,并读取并获取值 111,因为在该上下文中 this 是 doSomething() 方法的对象。 但是,整个列表数组是外部对象的成员。 outer 的另一个成员是 id,它是 list 的兄弟。如何从任何 doSomething() 方法的内部访问外部变量的 id?我唯一能想到的就是使用语法: var x = 外部.id; 但是知道该特定实例的变量名称的方法。

所以我必须创建一个函数来做这些事情,并在该函数中使用分配给对象的临时变量,并在 doSomething() 中引用该变量。

这是最好的方法吗?

[编辑] 我上面提到的我提出的解决方案如下所示:

var outer = {
    list: [
        {
            field1: 111,
            field2: 222,
            doSomething: function() {
                var x =outer.id;
            }
        },
        {
            field1: 333,
            field2: 444,
            doSomething: function() {
                var x =outer.id;
            }
        } 
    ],

    id: 0,
};

我试图避免内部对象知道标识符“外部”......但我想这是我们能做的最好的 --- 并且可能已经足够好了。

【问题讨论】:

    标签: javascript oop closures


    【解决方案1】:

    添加另一个包含对包含对象的引用的属性。

    var outer = {
        list: [
            {
                field1: 111,
                field2: 222,
                doSomething: function() {
                    var x = this.container.id;
                }
            },
            {
                field1: 333,
                field2: 444,
                doSomething: function() {
                    var x = this.container.id;
                }
            } 
        ],
    
        id: 0,
    };
    for (var i = 0; i < outer.list.length; i++) {
        outer.list[i].container = outer;
    }
    

    【讨论】:

      【解决方案2】:

      我认为你把问题复杂化了。如果idlist 中的每个项目中都相同,则它不需要包含在对象outer 中。您可以像这样简单地引用 id:

      var id = 0;
      
      var outer = {
          list: [
              {
                  field1: 111,
                  field2: 222,
                  doSomething: function() {
                      var x = id;
                      console.log(x);
                  }
              },
              {
                  field1: 333,
                  field2: 444,
                  doSomething: function() {
                      var x = id;
                      console.log(x);
                  }
              } 
          ]
      };
      
      outer.list[0].doSomething();
      outer.list[1].doSomething();
      

      如果需要,您甚至可以扩展 doSomething 函数以获取参数,然后为列表中的每个项目传递不同的值:

      doSomething: function(x) {
          console.log(x);
      }
      

      那么你可以这样称呼它:

      outer.list[0].doSomething(0);
      outer.list[1].doSomething(1);
      

      【讨论】:

        【解决方案3】:

        在 JavaScript 中没有向上关系,因为“子”对象可以有多个“父”对象:

        var outer = {
          inner = {"foo": "bar"}
        };
        
        var newOuter = {};
        newOuter.inner = outer.inner;
        
        // now inner is a property of both outer and newOuter
        

        由于您不能使用thisthis.parent 之类的关键字直接访问外部上下文,因此您必须使用其他选项。最好的办法是将上下文 (this) 作为参数传递给您的 doSomething 方法:

        var outer = {
          list: [
            {
              field1: 111,
              field2: 222,
              doSomething: function(context) {
                var x = context.id;
              }
            },
            {
              field1: 333,
              field2: 444,
              doSomething: function(context) {
                var x = context.id;
              }
            } 
          ],
          id: 0,
        };
        
        outer.list[0].doSomething(outer);
        

        正如其他人所提到的,您也可以将id 或上下文作为内部对象的属性存储在list 中。这种方法的缺点是会产生重复的代码,不是最优的。

        var outer = {
          list: [
            // version that stores context
            {
              context: outer,
              field1: 111,
              field2: 222,
              doSomething: function() {
                var x = this.context.id;
              }
            },
        
            // version that directly stores id
            {
              id: outer.id,
              field1: 333,
              field2: 444,
              doSomething: function() {
                var x = this.id;
              }
            } 
          ],
          id: 0,
        };
        

        您的第三个选择是使用 JavaScript 的变量范围规则将外部的 id 存储在最外部范围内的变量中,从而使其可供所有内部方法访问:

        var outer = {
          list: [
            {
              field1: 111,
              field2: 222,
              doSomething: function() {
                var x = id;
              }
            },
            {
              field1: 333,
              field2: 444,
              doSomething: function() {
                var x = id;
              }
            } 
          ],
          id: 0,
        };
        
        var id = outer.id;
        

        这样做的主要缺点是它可能会用不需要的变量污染你的外部范围,并打开你的内部对象,直到id 被更改的不需要的副作用。

        tl;博士:

        一般来说,面向对象编程的好处是模块化和封装性:您希望您的各种对象能够继续愉快地运行,而不管您对程序的其他部分进行了哪些更改。因此,最好通过将一个对象作为方法调用中的参数传递给另一个对象来处理对象之间的通信,从而使您可以将每个对象的逻辑与其他对象分开。因此,我建议定义您的内部对象,以便 doSomething() 方法接受 outer 对象的所需上下文作为参数;这将使您的代码具有可扩展性、灵活性和干性。

        【讨论】:

          【解决方案4】:

          您可以从使用 JavaScript 中的类中受益:

          function Outer(id) {
              this.id = id || 0;
              this.list = [];
          }
          
          Outer.prototype = {
              constructor: Outer,
          
              addItem: function(item) {
                  item.outer = this;
                  this.list.push(item);
              }
          };
          
          function Item(outer) {
              this.outer = outer || null;
          }
          
          Item.prototype = {
              field1: null,
              field2: null,
              outer: null
          
              constructor: Item,
          
              doSomething: function() {
                  alert(this.outer.id);
              }
          };
          

          并使用:

          var outer = new Outer(23);
          outer.addItem(new Item());
          outer.list[0].doSomething(); // alerts 23
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-12-21
            • 1970-01-01
            • 2021-08-22
            • 1970-01-01
            • 2023-03-23
            • 2021-08-18
            • 1970-01-01
            相关资源
            最近更新 更多