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

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

在当前的表单中,这段代码显然抛出了一个引用错误,因为它没有引用foo。但是有没有办法让对象字面量的属性值依赖于之前声明的其他属性呢?


当前回答

加上一个选项,因为我没有看到这种情况。如果您不希望在a或b更新时更新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

其他回答

我使用下面的代码作为替代,它工作。变量也可以是array。(@福斯托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]

你可以这样做

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定义为包含print函数的对象,允许函数引用该对象。这意味着如果您需要将print函数传递到其他地方,则不必将其“绑定”到对象。

如果您愿意,可以使用下面所示的方法

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的日志。

我认为下面的代码对于可维护性来说是最好的,尽管它不是在对象文字语法中:

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

这将使用{}创建一个新的空对象,然后使用匿名函数设置其属性(使用call()执行)。我认为唯一不好的部分是需要返回这个,感觉像是多了一行代码。不幸的是,我不能想出任何更好的方法来移动引用新创建的匿名对象到foo。

我认为这比语法var foo = new function(){…}因为它不会在原型链中创建一个额外的级别,就像@Bergi在一个现有答案的评论中解释的那样。

然而,如果这是真正的字面意思,没有任何其他逻辑,只有一个添加,它将更有意义的只是写

const foo = {
    a:5,
    b:6,
    c:11, // sum of a + b
};

因为不需要在运行时甚至编译时计算这个和。

加上一个选项,因为我没有看到这种情况。如果您不希望在a或b更新时更新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

这一切的关键是SCOPE。

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

记住这一点非常非常重要,如果你没有先这么做就引用了这个,那么这个就会引用外部作用域。这将是窗口对象。

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