【问题标题】:Self-references in object literals / initializers对象字面量/初始值设定项中的自引用
【发布时间】:2019-09-23 05:06:02
【问题描述】:

有什么方法可以让下面的东西在 JavaScript 中工作?

var foo = {
    a: 5,
    b: 6,
    c: this.a + this.b  // Doesn't work
};

在当前的形式中,由于this 没有引用foo,这段代码显然会抛出一个引用错误。但是是否有什么方法可以让对象字面量的属性中的值依赖于之前声明的其他属性?

【问题讨论】:

    标签: javascript object-literal


    【解决方案1】:

    嗯,我唯一能告诉你的就是getter

    var foo = {
      a: 5,
      b: 6,
      get c() {
        return this.a + this.b;
      }
    }
    
    console.log(foo.c) // 11

    这是 ECMAScript 第 5 版规范引入的语法扩展,大多数现代浏览器(包括 IE9)都支持该语法。

    【讨论】:

    • 非常有帮助的答案。有关“获取”的更多信息可以在这里找到:developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/…
    • 请注意,如果foo.afoo.b 的值发生更改,则foo.c 的值也会同步更改。这可能是也可能不是所需要的。
    • @HBP 这与问题中发生的情况完全相同,所以在我看来,这正是预期的结果。
    • 请注意,this 绑定到最深的嵌套对象。例如:... x: { get c () { /*this is x, not foo*/ } } ...
    • 为了完成我上面的陈述,因为foo被声明为一个变量并且c只会在它被调用的时候被评估,在foo里面使用c会起作用,而不是this(不过要小心)
    【解决方案2】:

    你可以这样做:

    var foo = {
       a: 5,
       b: 6,
       init: function() {
           this.c = this.a + this.b;
           return this;
       }
    }.init();
    

    这将是对象的某种一次性初始化。

    请注意,您实际上是将init() 的返回值分配给foo,因此您必须为return this

    【讨论】:

    • 你也可以在return this之前delete this.init,这样foo就不会被污染了
    • @BillyMoon:确实如此,尽管在许多引擎(例如 V8)上对该对象的所有后续属性访问都这样做了impacts performance
    • @MuhammadUmer:不确定 ES6 类如何与问题相关。
    • @MuhammadUmer:类只是构造函数的语法糖,所以它们并没有真正提供任何新东西。无论哪种方式,这个问题的主要焦点都是对象文字。
    • @akantoword: 太棒了 :) 因为对象字面量是单个表达式,所以 init() 调用直接附加了字面量以保持单个表达式。但是当然你可以单独调用你想要的函数。
    【解决方案3】:

    缺少明显、简单的答案,因此为了完整性:

    但是有没有办法让对象字面量的属性中的值依赖于之前声明的其他属性?

    没有。这里的所有解决方案都将其推迟到创建对象之后(以各种方式),然后分配第三个属性。 最简单的方法就是这样做:

    var foo = {
        a: 5,
        b: 6
    };
    foo.c = foo.a + foo.b;
    

    所有其他方法只是做同样事情的更间接的方式。 (Felix 特别聪明,但需要创建和销毁一个临时函数,增加了复杂性;并且要么在对象上留下额外的属性,要么 [如果你 delete 该属性] impacts the performance 对该对象的后续属性访问。)

    如果你需要它全部在一个表达式中,你可以在没有临时属性的情况下做到这一点:

    var foo = function(o) {
        o.c = o.a + o.b;
        return o;
    }({a: 5, b: 6});
    

    当然,如果您需要多次执行此操作:

    function buildFoo(a, b) {
        var o = {a: a, b: b};
        o.c = o.a + o.b;
        return o;
    }
    

    那么你需要在哪里使用它:

    var foo = buildFoo(5, 6);
    

    【讨论】:

    • 为了我自己的理智,我正在尝试找到某种官方文档,它说的基本相同 - 对象的 this 仅适用于 methods表示对象,没有其他种类的属性。知道我在哪里可以找到吗?谢谢!
    • @DavidKennell:没有比the specification 更正式的了。 :-) 你可能会从here 开始并坚持下去。这是一种相当尴尬的语言,但基本上你会在 Property Definition Evaluation 的各个子条款中看到,该对象不可用于确定属性初始值设定项值的操作。
    • 我看不到browserscope results here,但现在已经不是这样了,对吧?在我的环境中,v8: delete 快 10%,而 gecko : delete 仅慢 1%。
    • @TheMaster - 是的,我不认为 BrowserScope 真的是一个东西了。看起来删除不像以前那么糟糕了,至少在 V8(Chrome 等)或 SpiderMonkey 中没有。仍然慢,但只有一点点,而且这些天这些事情快得离谱。
    【解决方案4】:

    只需实例化一个匿名函数:

    var foo = new function () {
        this.a = 5;
        this.b = 6;
        this.c = this.a + this.b;
    };
    

    【讨论】:

    • @Bergi,为什么?因为有人可能会从中实例化另一个相同的对象?并不是说他们不能只克隆一个对象文字。这与传递 new Point(x, y) 之类的参数没有什么不同,只是该函数不是为重用而命名的。
    • @zzzzBov:他们当然可以克隆对象,但与 IEFE 解决方案(如 TJCrowder 的回答)相比,您的解决方案泄漏了构造函数并创建了一个多余的原型对象。
    • @zzzzBov:只需使用var foo = function() { this.…; return this; }.call({});,它在语法上并没有太大区别,但在语义上是合理的。
    • @Bergi,如果你觉得这很重要,为什么不添加你自己的答案呢?
    • 你有这个。我确实没有注意到new 关键字。
    【解决方案5】:

    现在在 ES6 中,您可以创建惰性缓存属性。首次使用时,该属性会评估一次以成为正常的静态属性。结果:第二次跳过了数学函数开销。

    魔术在吸气剂中。

    const foo = {
        a: 5,
        b: 6,
        get c() {
            delete this.c;
            return this.c = this.a + this.b
        }
    };
    

    在箭头获取器this 中选择surrounding lexical scope

    foo     // {a: 5, b: 6}
    foo.c   // 11
    foo     // {a: 5, b: 6 , c: 11}  
    

    【讨论】:

    • es5 还有一些属性,你只需要使用Object.defineProperty(foo, 'c', {get:function() {...}}) 来定义它们。在这样的工厂中,这很容易以一种不显眼的方式完成。当然,如果您可以使用 get 糖,它的可读性更高,但功能已经存在。
    • 这很好用,但我可以知道你为什么要在 this.c 不存在的时候删除它吗?我试过不写delete this.c,但没有用
    【解决方案6】:

    一些闭包应该解决这个问题;

    var foo = function() {
        var a = 5;
        var b = 6;
        var c = a + b;
    
        return {
            a: a,
            b: b,
            c: c
        }
    }();
    

    foo 中声明的所有变量都是foo 私有的,正如您对任何函数声明所期望的那样,并且因为它们都在范围内,所以它们都可以相互访问而无需引用this,就像你对函数的期望一样。不同之处在于此函数返回一个对象,该对象公开私有变量并将该对象分配给foo。最后,您只返回您想要使用return {} 语句作为对象公开的接口。

    该函数在最后以() 执行,这会导致评估整个 foo 对象,实例化内的所有变量并将返回对象添加为foo() 的属性。

    【讨论】:

    • 将其称为“关闭”是令人困惑和误导的。尽管人们对从函数返回对象值的确切含义存在不同意见,但这并不构成任何人的书中的闭包。
    【解决方案7】:

    你可以这样做

    var a, b
    var foo = {
        a: a = 5,
        b: b = 6,
        c: a + b
    }
    

    当我不得不引用最初声明函数的对象时,该方法对我很有用。以下是我如何使用它的最小示例:

    function createMyObject() {
        var count = 0, self
        return {
            a: self = {
                log: function() {
                    console.log(count++)
                    return self
                }
            }
        }
    }
    

    通过将 self 定义为包含打印函数的对象,您允许该函数引用该对象。这意味着如果您需要将它传递给其他地方,您不必将打印函数“绑定”到一个对象。

    如果您愿意,请改用this,如下图所示

    function createMyObject() {
        var count = 0
        return {
            a: {
                log: function() {
                    console.log(count++)
                    return this
                }
            }
        }
    }
    

    那么下面的代码会记录0、1、2然后报错

    var o = createMyObject()
    var log = o.a.log
    o.a.log().log() // this refers to the o.a object so the chaining works
    log().log() // this refers to the window object so the chaining fails!
    

    通过使用 self 方法,您可以保证 print 将始终返回相同的对象,而不管函数运行的上下文。当使用 createMyObject() 的 self 版本时,上面的代码将运行良好并记录 0、1、2 和 3。

    【讨论】:

      【解决方案8】:

      为了完成,在 ES6 中我们有类(在撰写本文时仅支持最新的浏览器,但在 Babel、TypeScript 和其他转译器中可用)

      class Foo {
        constructor(){
          this.a = 5;
          this.b = 6;
          this.c = this.a + this.b;
        }  
      }
      
      const foo = new Foo();
      

      【讨论】:

        【解决方案9】:

        只是为了思考 - 将对象的属性放在时间轴之外:

        var foo = {
            a: function(){return 5}(),
            b: function(){return 6}(),
            c: function(){return this.a + this.b}
        }
        
        console.log(foo.c())
        

        上面也有更好的答案。这就是我修改您质疑的示例代码的方式。

        更新:

        var foo = {
            get a(){return 5},
            get b(){return 6},
            get c(){return this.a + this.b}
        }
        // console.log(foo.c);
        

        【讨论】:

        • 在 ES6 中,您可以使这种通用方法更加优雅:var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} } 所以现在您可以使用 foo.c 而不是 foo.c() :) (请随意将其粘贴到您的答案中,以便格式化更好!)
        【解决方案10】:

        您可以使用模块模式来做到这一点。就像:

        var foo = function() {
          var that = {};
        
          that.a = 7;
          that.b = 6;
        
          that.c = function() {
            return that.a + that.b;
          }
        
          return that;
        };
        var fooObject = foo();
        fooObject.c(); //13
        

        使用此模式,您可以根据需要实例化多个 foo 对象。

        http://jsfiddle.net/jPNxY/1/

        【讨论】:

        • 这不是模块模式的例子,只是一个函数。如果 foo 定义的最后一行是}();,它将自行执行并返回一个对象,而不是一个函数。此外,foo.c 是一个函数,因此写入它会破坏该函数,并且通过 fooObject.c() 进行的下一次调用将失败。也许这个fiddle 更接近你想要的(它也是一个单例,不是为了实例化而设计的)。
        • “模块模式最初被定义为一种为传统软件工程中的类提供私有和公共封装的方法”。来自:Learning JavaScript Design Patterns。该对象遵循上述模块模式,但可能不是最好的解释,因为它没有显示公共和私有属性/方法。这个jsfiddle.net/9nnR5/2 是具有公共和私有属性/方法的同一个对象。所以他们俩都遵循这种模式
        【解决方案11】:

        有几种方法可以做到这一点;这就是我要使用的:

        function Obj() {
         this.a = 5;
         this.b = this.a + 1;
         // return this; // commented out because this happens automatically
        }
        
        var o = new Obj();
        o.b; // === 6
        

        【讨论】:

        • 这可行,但消除了对象文字表示法的优点。
        • 是的,对不起,我最初错过了 object-literal 标记。我大多只将对象字面量用于数据结构,并且每当我想要任何额外的逻辑(可能类似于类)时,我都会出于这个原因将对象创建为函数的结果。
        【解决方案12】:

        在对象字面量上创建新函数并调用构造函数似乎与原始问题完全不同,而且没有必要。

        在对象字面量初始化期间,您不能引用同级属性。

        var x = { a: 1, b: 2, c: a + b } // not defined 
        var y = { a: 1, b: 2, c: y.a + y.b } // not defined 
        

        计算属性的最简单解决方案如下(无堆、无函数、无构造函数):

        var x = { a: 1, b: 2 };
        
        x.c = x.a + x.b; // apply computed property
        

        【讨论】:

          【解决方案13】:

          此处发布的其他答案更好,但这是另一种选择:

          • 在初始化时设置值(不是 getter 或派生等)
          • 不需要任何类型的 init() 或对象字面量之外的代码
          • 是对象字面量,而不是工厂函数或其他对象创建机制。
          • 不应有任何性能影响(初始化时除外)

          自执行匿名函数和窗口存储

          var foo = {
              bar:(function(){
                  window.temp = "qwert";
                  return window.temp;
              })(),
              baz: window.temp
          };
          

          顺序是guaranteedbarbaz 之前)。

          它当然会污染window,但我无法想象有人编写需要window.temp 才能持久的脚本。如果你偏执,也许tempMyApp

          它也很丑,但偶尔有用。例如,当您使用的 API 具有严格的初始化条件并且不想重构,因此范围界定是正确的。

          当然是干的。

          【讨论】:

            【解决方案14】:

            这一切的关键是SCOPE

            您需要将要定义的属性的“父”(父对象)封装为它自己的实例化对象,然后您可以使用关键字this来引用兄弟属性

            非常非常重要要记住,如果您在没有首先这样做的情况下引用this,那么this 将引用外部范围......这将是window对象。

            var x = 9   //this is really window.x
            var bar = {
              x: 1,
              y: 2,
              foo: new function(){
                this.a = 5, //assign value
                this.b = 6,
                this.c = this.a + this.b;  // 11
              },
              z: this.x   // 9 (not 1 as you might expect, b/c *this* refers `window` object)
            };
            

            【讨论】:

              【解决方案15】:

              如果您的对象被编写为返回对象的函数,并且您使用 ES6 对象属性“方法”,那么它是可能的:

              const module = (state) => ({
                a: 1,
                oneThing() {
                  state.b = state.b + this.a
                },
                anotherThing() {
                  this.oneThing();
                  state.c = state.b + this.a
                },
              });
              
              const store = {b: 10};
              const root = module(store);
              
              root.oneThing();
              console.log(store);
              
              root.anotherThing();
              console.log(store);
              
              console.log(root, Object.keys(root), root.prototype);
              

              【讨论】:

                【解决方案16】:

                我使用以下代码作为替代,它可以工作。变量也可以是数组。 (@Fausto R.)

                var foo = {
                  a: 5,
                  b: 6,
                  c: function() {
                    return this.a + this.b;
                  },
                
                  d: [10,20,30],
                  e: function(x) {
                    this.d.push(x);
                    return this.d;
                  }
                };
                foo.c(); // 11
                foo.e(40); // foo.d = [10,20,30,40]
                

                【讨论】:

                  【解决方案17】:

                  这是一个简洁的 ES6 方式:

                  var foo = (o => ({
                      ...o,
                      c: o.a + o.b
                    }))({
                      a: 5,
                      b: 6
                    });
                    
                  console.log(foo);

                  我用它来做这样的事情:

                  const constants = Object.freeze(
                    (_ => ({
                      ..._,
                      flag_data: {
                        [_.a_flag]: 'foo',
                        [_.b_flag]: 'bar',
                        [_.c_flag]: 'oof'
                      }
                    }))({
                      a_flag: 5,
                      b_flag: 6,
                      c_flag: 7,
                    })
                  );
                  
                  console.log(constants.flag_data[constants.b_flag]);

                  【讨论】:

                    【解决方案18】:

                    get 属性效果很好,您还可以为“昂贵”的函数使用绑定闭包,这些函数只能运行一次 (这只适用于 var,不适用于 constlet )

                    var info = {
                      address: (function() {
                        return databaseLookup(this.id)
                      }).bind(info)(),
                    
                      get fullName() {
                        console.log('computing fullName...')
                        return `${this.first} ${this.last}`
                      },
                    
                      id: '555-22-9999',
                      first: 'First',
                      last: 'Last',
                    }
                    
                    function databaseLookup() {
                      console.log('fetching address from remote server (runs once)...')
                      return Promise.resolve(`22 Main St, City, Country`)
                    }
                    
                    // test
                    (async () => {
                      console.log(info.fullName)
                      console.log(info.fullName)
                      console.log(await info.address)
                      console.log(await info.address)
                      console.log(await info.address)
                      console.log(await info.address)
                    })()

                    【讨论】:

                      【解决方案19】:

                      这个解决方案怎么样,它也适用于带有数组的嵌套对象

                            Object.prototype.assignOwnProVal
                           = function (to,from){ 
                                  function compose(obj,string){ 
                                      var parts = string.split('.'); 
                                      var newObj = obj[parts[0]]; 
                                      if(parts[1]){ 
                                          parts.splice(0,1);
                                          var newString = parts.join('.'); 
                                          return compose(newObj,newString); 
                                      } 
                                      return newObj; 
                                  } 
                                  this[to] = compose(this,from);
                           } 
                           var obj = { name : 'Gaurav', temp : 
                                        {id : [10,20], city:
                                              {street:'Brunswick'}} } 
                           obj.assignOwnProVal('street','temp.city.street'); 
                           obj.assignOwnProVal('myid','temp.id.1');
                      

                      【讨论】:

                        【解决方案20】:

                        加入一个选项,因为我没有看到这个确切的场景。如果您希望在 ab 更新时更新 c,那么 ES6 IIFE 可以正常工作。

                        var foo = ((a,b) => ({
                            a,
                            b,
                            c: a + b
                        }))(a,b);
                        

                        根据我的需要,我有一个与数组相关的对象,该数组最终将在循环中使用,所以我只想计算一些常用设置,所以这就是我所拥有的:

                        let processingState = ((indexOfSelectedTier) => ({
                            selectedTier,
                            indexOfSelectedTier,
                            hasUpperTierSelection: tiers.slice(0,indexOfSelectedTier)
                                                 .some(t => pendingSelectedFiltersState[t.name]),
                        }))(tiers.indexOf(selectedTier));
                        

                        由于我需要为indexOfSelectedTier 设置一个属性,并且在设置hasUpperTierSelection 属性时需要使用该值,所以我首先计算该值并将其作为参数传递给IIFE

                        【讨论】:

                          【解决方案21】:

                          其他方法是先声明对象,然后再为其分配属性:

                          const foo = {};
                          foo.a = 5;
                          foo.b = 6;
                          foo.c = foo.a + foo.b;  // Does work
                          foo.getSum = () => foo.a + foo.b + foo.c;  // foo.getSum() === 22
                          

                          这样,您可以使用对象变量名称来访问已分配的值。
                          最适合config.js 文件。

                          【讨论】:

                          • 这不是自引用,而是对声明的变量foo 的引用,它指向有问题的对象。
                          【解决方案22】:

                          如果你想使用原生 JS,其他答案提供了很好的解决方案。

                          但如果您愿意编写自引用对象,例如:

                          { 
                            a: ...,
                            b: "${this.a + this.a}",
                          }
                          

                          我编写了一个名为 self-referenced-object 的 npm 库,它支持该语法并返回一个原生对象。

                          【讨论】:

                          • avoid link only answers。答案“仅仅是指向外部网站的链接”may be deleted
                          • @Quentin 你对如何改进我的答案有什么建议吗?这个问题的其他答案涵盖了您如何能够在本机 javascript 中编写自引用对象,但是如果您想使用类似于海报原始问题中的语法的语法编写自引用对象,我认为该库我写的可能对寻找解决方案的其他人有用。很高兴得到一些反馈。
                          • 这里有几个需要改进的地方。首先,也是最明显的,您使用的是没有反引号的模板文字语法。您的b 属性值应为:${this.a + this.a}。其次,但不太重要的是,您希望使用parseInt 之类的东西返回一个数字,而不是字符串。最后也是最重要的是,当我尝试这个示例时,它根本不起作用,原因与 OP 要求的原因相同。 this 在使用它自己的对象声明时返回 undefined。 @alex-e-leon
                          • @AlecDonaldMather - 感谢您抽出宝贵时间查看并提供一些反馈!如果您对该项目感兴趣,最好将此讨论转移到 github,但要回答您的一些反馈: - 使用反引号:如之前的 cmets 所述,JS 不支持此语法,因此使用字符串代替这里需要反引号,以避免 js 在定义 obj 之前尝试解析“this” - 返回一个数字,如果 a + b 已经是数字,这应该可以工作,因为如果 a 和 b 都是,a + b 将返回一个数字已经编号了。
                          • Re this return undefined,你能解释一下你是如何尝试使用这个库的吗?这不应该发生,但也许我遗漏了一个边缘情况?也就是说,这个库并没有完全解决问题,并且有自己的权衡,但如果你有兴趣帮助我改进它/使用它,请告诉我!
                          【解决方案23】:

                          这是对象中“this”行为的示例。

                          this.prop = 'external';
                          global.prop = 'global.prop';
                          const that = this;
                          
                          const a = {
                            prop: 'internal',
                            prop1: this.prop, //external
                          
                            log() {
                              return this.prop //internal
                            },
                            log1: () => {
                              return this.prop //external
                            },
                            log2: () => {
                              return function () {
                                return this.prop; //'global.prop' in node; 'external' in chrome
                              }()
                            },
                            log3: function () {
                              return (() => {
                                return this.prop; //internal
                              })()
                            },
                          }
                          

                          【讨论】:

                            【解决方案24】:

                            注意:此解决方案使用 Typescript(如果需要,您可以使用 TS 编译成的 vanilla JS)

                            class asd {
                                def = new class {
                                    ads= 'asd';
                                    qwe= this.ads + '123';
                                };
                            
                                // this method is just to check/test this solution 
                                check(){
                                    console.log(this.def.qwe);
                                }
                            }
                            
                            // these two lines are just to check
                            let instance = new asd();
                            instance.check();
                            

                            这里使用类表达式来获得我们想要的嵌套对象字面量接口。恕我直言,这是在创建期间能够引用对象的属性的下一个最好的事情。

                            主要需要注意的是,在使用此解决方案时,您的界面与从对象字面量中获得的界面完全相同。而且语法非常接近对象文字本身(与使用函数等相比)。

                            比较以下

                            我提出的解决方案

                            class asd {
                                def = new class {
                                    ads= 'asd';
                                    qwe= this.ads + '123';
                                };
                            

                            如果对象字面量足够了的解决方案

                            var asd = {
                                def : {
                                    ads:'asd',
                                    qwe: this.ads + '123';, //ILLEGAL CODE; just to show ideal scenario
                                }
                            }
                            

                            另一个例子

                            在这个类中,你可以组合多个相互之间的相对路径,这对于对象字面量是不可能的。

                            class CONSTANT {
                                static readonly PATH = new class {
                                    /** private visibility because these relative paths don't make sense for direct access, they're only useful to path class
                                     *
                                     */
                                    private readonly RELATIVE = new class {
                                        readonly AFTER_EFFECTS_TEMPLATE_BINARY_VERSION: fs.PathLike = '\\assets\\aep-template\\src\\video-template.aep';
                                        readonly AFTER_EFFECTS_TEMPLATE_XML_VERSION: fs.PathLike = '\\assets\\aep-template\\intermediates\\video-template.aepx';
                                        readonly RELATIVE_PATH_TO_AFTER_EFFECTS: fs.PathLike = '\\Adobe\\Adobe After Effects CC 2018\\Support Files\\AfterFX.exe';
                                        readonly OUTPUT_DIRECTORY_NAME: fs.PathLike = '\\output';
                                        readonly INPUT_DIRECTORY_NAME: fs.PathLike = '\\input';
                                        readonly ASSETS_DIRECTORY_NAME: fs.PathLike = '\\assets';
                                    };
                                }
                            }
                            

                            【讨论】:

                            • 会不会是因为你的回答完全不相关?我同意投反对票的人应该解释,但你的回答清楚与问题无关……
                            • @Manngo 感谢您指出这一点。老实说,我和 OP 有同样的问题,我使用了我建议的解决方案。不确定,为什么它被认为是无关紧要的。如果您有时间,请解释一下,以便我可以更好地回答或至少知道我错在哪里。不幸的是,我不明白为什么这不是一个合理的解决方案。
                            • 这根本没有解决自引用的问题。您提出的是一种通过在代码中引入不必要的闭包来模拟自我引用的相当复杂的方式。
                            【解决方案25】:

                            两个懒惰的解决方案

                            这里已经有很好的答案,我不是这方面的专家,但我是懒惰专家,在我的专家眼中,这些答案似乎不够懒惰。

                            首先:从匿名函数返回对象

                            答案与T.J. CrowderHenry WrightsonRafael Rocha 略有不同:

                            var foo = (() => {
                            
                              // Paste in your original object
                              const foo = {
                                a: 5,
                                b: 6,
                              };
                              
                              // Use their properties
                              foo.c = foo.a + foo.b;
                            
                              // Do whatever else you want
                            
                              // Finally, return object
                              return foo;
                            })();
                            
                            console.log(foo);

                            这里的轻微优势只是粘贴原始对象,而不用担心参数等。(恕我直言,包装函数通过这种方式变得非常透明)。

                            第二:使用setTimeout

                            如果您不需要foo.c,这可能会起作用:

                            var foo = {
                              a: 5,
                              b: 6,
                              c: setTimeout(() => foo.c = foo.a + foo.b, 0)
                            };
                            
                            // Though, at first, foo.c will be the integer returned by setTimeout
                            console.log(foo);
                            // But if this isn't an issue, the value will be updated when time comes in the event loop
                            setTimeout( () => console.log(foo), 0);

                            【讨论】:

                              【解决方案26】:
                              var x = {
                                  a: (window.secreta = 5),
                                  b: (window.secretb = 6),
                                  c: window.secreta + window.secretb
                              };
                              

                              这与@slicedtoad 的答案几乎相同,但不使用函数。

                              【讨论】:

                                猜你喜欢
                                相关资源
                                最近更新 更多