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

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

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


当前回答

两种惰性解决方案

这里已经有了很好的答案,我不是这方面的专家,但我是懒惰方面的专家,以我的专家眼光来看,这些答案似乎不够懒惰。

第一个:从匿名函数返回对象

T.J. Crowder, Henry Wrightson和Rafael Rocha的回答略有不同:

Var foo = (() => { //粘贴原始对象 Const foo = { 5, b: 6, }; //使用它们的属性 foo.c = foo。A + foo.b; //做任何你想做的事情 //最后返回对象 返回foo; }) (); console.log (foo);

稍微有点好处的是,只需要原样粘贴您的原始对象,而不用担心参数等(恕我直言,包装器函数通过这种方式变得相当透明)。

第二:使用setTimeout

如果你不需要立即使用foo.c,这个方法可以工作:

Var foo = { 5, b: 6, c: setTimeout(() => foo.c = foo.c。A + foo。b, 0) }; //首先,foo.c将是setTimeout返回的整数 console.log (foo); //但如果这不是一个问题,当时间进入事件循环时,值将被更新 setTimeout(() => console.log(foo), 0);

其他回答

只是为了大家的娱乐:

var foo = (This={ 5, b: 6,})=>({… c:。a +这个。b }))( ); console.log (foo);

注意:这个解决方案使用Typescript(如果需要,你可以使用TS编译的普通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';
        };
    }
}

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

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

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

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

我唯一能告诉你的是getter

Var foo = { 5, b: 6, 获取c() { 返回。A + this.b; } } Console.log (foo.c) // 11

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

好吧,我想到了另一个解决方案。这里我想初始化一个对象,表示每个时间单位的毫秒数。 结果是typescript中的enum在我的例子中不能使用,所以我声明了多个变量,并将其分配给一个对象,如下所示:

const SECOND = 1000
const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR
const WEEK = 7 * DAY

export const TimeInMS = {
  SECOND,
  MINUTE,
  HOUR,
  DAY,
  WEEK
}

这种方法的缺点是:

变量被定义为常量,即使我们不需要它们。因此它需要无用的内存。 对象的每个值必须声明为独立的变量