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

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

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


当前回答

现在在ES6中,你可以创建惰性缓存属性。在第一次使用时,该属性只计算一次,成为一个正常的静态属性。结果:第二次跳过数学函数开销。

神奇之处在于getter。

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

在箭头getter中,这将拾取周围的词法作用域。

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 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

get属性工作得很好,你也可以对只运行一次的“昂贵”函数使用绑定闭包(这只适用于var,而不适用于const或let)

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

显而易见,简单的答案是缺失的,所以为了完整:

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

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

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

其他的都是做同样事情的更间接的方式。(Felix的方法特别聪明,但需要创建和销毁临时函数,这增加了复杂性;并且要么在对象上留下额外的属性,要么[如果删除该属性]影响该对象上后续属性访问的性能。)

如果你需要它都在一个表达式中,你可以不使用temporary属性:

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

只是为了思考-地点对象的属性的时间轴:

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

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

但是如果你愿意写自引用对象,比如:

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

我写了一个叫做self- references -object的npm库,它支持这种语法并返回一个原生对象。