Answers:
好吧,我唯一能告诉你的就是吸气剂:
var foo = {
a: 5,
b: 6,
get c() {
return this.a + this.b;
}
}
console.log(foo.c) // 11
这是ECMAScript第5版规范引入的语法扩展,大多数现代浏览器(包括IE9)都支持该语法。
foo.a
或的值foo.b
被更改,则的值foo.c
也将同步更改。这可能是必需的,也可能不是。
this
绑定到最深的嵌套对象。例如:... x: { get c () { /*this is x, not foo*/ } } ...
foo
beeing被声明为变量,并且c
仅在调用它时才被评估,因此使用foo
inside c
可以起作用,而不是this
(尽管要小心)
您可以执行以下操作:
var foo = {
a: 5,
b: 6,
init: function() {
this.c = this.a + this.b;
return this;
}
}.init();
这将是对象的某种一次性初始化。
请注意,您实际上是在分配init()
to 的返回值foo
,因此必须return this
。
delete this.init
之前return this
,这样foo
是不是poluted
init()
调用直接附加到文字之后以使其保持单个表达式。但是当然您可以根据需要单独调用该函数。
缺少显而易见的简单答案,因此出于完整性考虑:
但是,是否有任何方法可以使对象文字的属性值取决于先前声明的其他属性?
否。这里的所有解决方案都将其推迟到创建对象之后(以各种方式),然后分配第三个属性。在最简单的方法是只是这样做:
var foo = {
a: 5,
b: 6
};
foo.c = foo.a + foo.b;
所有其他方法只是做同一件事的更间接的方法。(Felix的技巧特别聪明,但是需要创建和销毁一个临时函数,从而增加了复杂性;并且要么在对象上留下额外的属性,要么[如果您使用delete
该属性]会影响对该对象的后续属性访问的性能。)
如果需要全部包含在一个表达式中,则可以在没有临时属性的情况下执行此操作:
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
只能用于该对象的方法,而不能使用其他类型的属性。知道在哪里可以找到吗?谢谢!
只需实例化一个匿名函数:
var foo = new function () {
this.a = 5;
this.b = 6;
this.c = this.a + this.b;
};
new Point(x, y)
除了函数没有为重用而命名。
var foo = function() { this.…; return this; }.call({});
语法上没有太大区别但在语义上理智的即可。
new
关键字。
现在,在ES6中,您可以创建惰性缓存的属性。首次使用时,该属性会评估一次,成为普通的静态属性。结果:第二次跳过数学函数开销。
魔术是吸气剂。
const foo = {
a: 5,
b: 6,
get c() {
delete this.c;
return this.c = this.a + this.b
}
};
箭头中的getter this
拾取了周围的词汇范围。
foo // {a: 5, b: 6}
foo.c // 11
foo // {a: 5, b: 6 , c: 11}
Object.defineProperty(foo, 'c', {get:function() {...}})
用来定义它们的属性。在这样的工厂中,这很容易以不干扰的方式完成。当然,如果可以使用get
糖,它的可读性更高,但功能已经存在。
一些关闭应该处理这个问题;
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()
。
你可以这样
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始终返回相同的对象,而不管函数在哪个上下文中运行。当使用的自我版本时,上面的代码可以正常运行并记录0、1、2和3 createMyObject()
。
您可以使用模块模式来实现。就像:
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对象。
有几种方法可以做到这一点。这就是我会用的:
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
只是为了考虑-将对象的属性放在时间轴之外:
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);
此处发布的其他答案更好,但这是一个替代方法:
init()
对象文字之外的任何类型或代码自执行匿名功能和窗口存储
var foo = {
bar:(function(){
window.temp = "qwert";
return window.temp;
})(),
baz: window.temp
};
订单得到保证(bar
之前baz
)。
它window
当然会污染,但我无法想象有人编写需要window.temp
持久化的脚本。也许tempMyApp
你是偏执狂。
它也很丑陋,但偶尔有用。一个示例是当您使用具有严格初始化条件的API且不想进行重构时,因此作用域是正确的。
当然是干的。
这一切的关键是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)
};
如果将您的对象编写为返回对象的函数,并且使用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);
这是一种整洁的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]);
这个解决方案如何也可以用于带有数组的嵌套对象
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');
因为我没有看到这个确切的场景,所以选择了一个选项。如果你不做要c
更新时a
或b
更新,那么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
注意:此解决方案使用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';
};
}
}
如果要使用本机JS,则其他答案将提供良好的解决方案。
但是,如果您愿意编写类似以下内容的自引用对象:
{
a: ...,
b: "${this.a + this.a}",
}
我编写了一个名为自我引用对象的npm库,该库支持该语法并返回一个本机对象。
b
财产的价值应为:${this.a + this.a}
。其次,但更不重要的是,您想使用来返回数字,而不是字符串parseInt
。最后一点,也是最重要的一点,当我尝试这个示例时,由于OP询问的相同原因,它根本不起作用。this
使用自己的对象声明时,返回undefined。@ alex-e-leon