有什么方法可以让下面的东西在JavaScript中工作?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
在当前的表单中,这段代码显然抛出了一个引用错误,因为它没有引用foo。但是有没有办法让对象字面量的属性值依赖于之前声明的其他属性呢?
有什么方法可以让下面的东西在JavaScript中工作?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Doesn't work
};
在当前的表单中,这段代码显然抛出了一个引用错误,因为它没有引用foo。但是有没有办法让对象字面量的属性值依赖于之前声明的其他属性呢?
当前回答
另一种方法是在给对象赋值之前先声明对象:
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文件。
其他回答
var x = {
a: (window.secreta = 5),
b: (window.secretb = 6),
c: window.secreta + window.secretb
};
这与@slicedtoad的答案几乎相同,但没有使用函数。
注意:这个解决方案使用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);
好吧,我想到了另一个解决方案。这里我想初始化一个对象,表示每个时间单位的毫秒数。 结果是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
}
这种方法的缺点是:
变量被定义为常量,即使我们不需要它们。因此它需要无用的内存。 对象的每个值必须声明为独立的变量
我认为下面的代码对于可维护性来说是最好的,尽管它不是在对象文字语法中:
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
};
因为不需要在运行时甚至编译时计算这个和。