【问题标题】:JavaScript object with internally referenced properties具有内部引用属性的 JavaScript 对象
【发布时间】:2010-09-18 22:31:33
【问题描述】:

我正在尝试创建一个具有一系列“从属”属性的全局对象,这些“从属”属性派生自同一对象中一个“主”属性的值 - 类似于:

var x = 5;
var myObj = {
    master : 17,
    slave1 : this.master + x,
    slave2 : (this.master / 2.2) + 1,
    slave3 : Math.floor(this.slave2)
    //etc.
};

我意识到这是非常错误的,但这个概念是存在的。我想做的是在更新myObj.master 时更新所有这些“从属”属性。最干净的方法是什么?当myObj.master 更改时,每个从属值是否需要由某个事件处理程序显式设置...?

【问题讨论】:

    标签: javascript object properties global


    【解决方案1】:

    如果您的目标不是 Internet Explorer 用户,请尝试使用 getter 和 setter。

    var x = 5;
    function myObj()
    {
        this.master = 17;
        this.getSlave1 = function() {return this.master + x;},
        this.getSlave2 = function() {return (this.master / 2.2) + 1;},
        this.getSlave3 = function() {return Math.floor(this.getSlave2());}
    }
    
    myObj.prototype = {
        get slave1() {
            return this.getSlave1();
        },
        get slave2() {
            return this.getSlave2();
        },
        get slave3() {
            return this.getSlave3();
        }
    };   
    

    在行动:

    window.onload = function()
    {
        o = new myObj();
        document.write("Master: "+o.master+"</br>");
        document.write("Slave 1: "+o.slave1+"</br>");
        document.write("Slave 2: "+o.slave2+"</br>");
        document.write("Slave 3: "+o.slave3+"</br></br>");
        o.master = 42;
        document.write("Master: "+o.master+"</br>");
        document.write("Slave 1: "+o.slave1+"</br>");
        document.write("Slave 2: "+o.slave2+"</br>");
        document.write("Slave 3: "+o.slave3+"</br>");
    }
    

    产生输出:

    Master: 17
    Slave 1: 22
    Slave 2: 8.727272727272727
    Slave 3: 8
    
    Master: 42
    Slave 1: 47
    Slave 2: 20.09090909090909
    Slave 3: 20
    

    此代码永远不会在任何版本的 Internet Explorer(过去、现在或将来)中工作。但是,仍然可以使用getSlaveX() 函数访问从属值。

    【讨论】:

    • 我觉得这样容易出错。您在两个地方都有公式,并且可以在不更改主机的情况下更改从机。
    • @mangoDrunk:很好,我更新了代码,只使用 getter 来检索从属值,使它们成为只读的,并且使公式只输入一次。
    • @Andrew Dunn:看起来不错。我不知道 get/set,它很可爱。
    • Andrew,getter 可能会在 IE 9 中工作,因为这次他们实际上编写了一个不错的引擎。
    • IE8 仅将 Object.defineProperty 用于 DOM 对象,而在 IE9 中很可能允许将其用于 javascript 对象。由于上面的代码没有使用 Object.defineProperty 方法,所以很可能是行不通的。
    【解决方案2】:

    你可能最好使用函数。

    var x = 5;
    var myObj = {
        master : 17,
        slave1 : function() { return this.master + x },
        slave2 : function() { return (this.master / 2.2) + 1 },
        slave3 : function() { return Math.floor(this.slave2()); }
        //etc.
    };
    
    var example = myObj.slave3();
    

    【讨论】:

      【解决方案3】:

      大卫的回答是一种选择,但如果你想缓存结果而不是每次都重新计算,那就反过来做:

      var x = 5;
      var myObj = {
          setMaster: function(val) {
              this.master = val;
              this.slave1 = this.master + x;
              // ...
          }
      };
      
      myObj.setMaster(17);
      

      【讨论】:

      • 如果您要采用这种方法,我希望将主属性作为私有成员,因此不能直接设置它导致从属属性错误。您必须用构造函数替换文字对象表示法。
      【解决方案4】:

      另一种选择是使用构造函数来构建您的对象,例如:

      var x = 5;
      
      function MyObj(master) {
        this.master = master;
        this.slave1 = this.master + x,
        this.slave2 = (this.master / 2.2) + 1,
        this.slave3 = Math.floor(this.slave2)
      }
      
      var myObj = new MyObj(17);
      

      在上面的示例中,我使用了master 参数和对x 全局属性的引用,如果您在该范围内没有可用的x,您也可以为其提供一个参数。

      您还可以通过几个步骤构建您的对象:

      var myObj = {
          master : 17
      }, x = 5;
      
      myObj.slave1 = myObj.master + x;
      myObj.slave2 = (myObj.master / 2.2) + 1;
      myObj.slave3 = Math.floor(myObj.slave2);
      

      【讨论】:

        【解决方案5】:

        您不想暴露从属并允许设置它们,因为这会删除它们与主控的链接。所以它们应该是私有的。

        var x = 5;
        var MyObject = function() {
            var master = 17;
            this.setMaster = function(newMaster) {
                master = newMaster;
            };
            this.getMaster = function() {
                return master;
            };
            var slaves = {
                slave1 : function() { return master + x },
                slave2 : function() { return (master / 2.2) + 1 },
                slave3 : function() { return Math.floor(this.slave2()) }
            };
            this.getSlave = function(slave) {
                return slaves[slave]();
            };
        };
        
        var o = new MyObject();
        o.getSlave("slave1"); // 22
        o.getSlave("slave3"); // 8
        o.setMaster(3);
        o.getSlave("slave1"); // 8
        o.getSlave("slave3"); // 2
        

        【讨论】:

          【解决方案6】:

          您可以使用valueOftoString 模拟getter,但它有点笨拙。

          function makeValueOf(fn) {
              return {
                  valueOf: fn,
                  toString: fn
              };
          }
          
          function makeObj(master, x) {
              var self = {};
          
              self.master = master;
              self.slave1 = makeValueOf(function () { return self.master + x; });
              self.slave2 = makeValueOf(function () { return self.master / 2.2 + 1; });
              self.slave3 = makeValueOf(function () { return Math.floor(self.slave2); });
          
              return self;
          }
          
          var myObj = makeObj(6, 2);
          alert(myObj.slave1 + 5); // 13
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-02-02
            • 1970-01-01
            • 1970-01-01
            • 2011-11-06
            相关资源
            最近更新 更多