Self-references in object literals / initializers

2019-08-05 23:48发布

Is there any way to get something like the following to work in JavaScript?

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

In the current form, this code obviously throws a reference error since this doesn't refer to foo. But is there any way to have values in an object literal's properties depend on other properties declared earlier?

23条回答
我想做一个坏孩纸
2楼-- · 2019-08-06 00:34

just for the sake of thought - place object's properties out of a timeline:

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

console.log(foo.c())

there are better answers above too. This is how I modified example code you questioned with.

UPDATE:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);
查看更多
Animai°情兽
3楼-- · 2019-08-06 00:35

The obvious, simple answer is missing, so for completeness:

But is there any way to have values in an object literal's properties depend on other properties declared earlier?

No. All of the solutions here defer it until after the object is created (in various ways) and then assign the third property. The simplest way is to just do this:

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

All others are just more indirect ways to do the same thing. (Felix's is particularly clever, but requires creating and destroying a temporary function, adding complexity; and either leaves an extra property on the object or [if you delete that property] impacts the performance of subsequent property accesses on that object.)

If you need it to all be within one expression, you can do that without the temporary property:

var foo = function(o) {
    o.c = o.a + o.b;
    return o;
}({a: 5, b: 6});

Or of course, if you need to do this more than once:

function buildFoo(a, b) {
    var o = {a: a, b: b};
    o.c = o.a + o.b;
    return o;
}

then where you need to use it:

var foo = buildFoo(5, 6);
查看更多
成全新的幸福
4楼-- · 2019-08-06 00:35

How about this solution this will work with nested objects with array as well

      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');
查看更多
来,给爷笑一个
5楼-- · 2019-08-06 00:35

A different approach, to keep things a bit simpler and not define new functions in the object, is to keep the original object with its properties, create a second object with the dynamic properties that use the first object's properties and then merge using spread.

So:

Object

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

Object 2

var foo2 = {
    c: foo.a + foo.b
};

Merge

Object.assign(foo, foo2);

or

foo = {...foo, ...foo2};

Result of foo:

{ 
  "a":5,
  "b":6,
  "c":11
}

All within the same js, no new functions within the object, only using assign or spread.

查看更多
闹够了就滚
6楼-- · 2019-08-06 00:42

Other approach would be to declare the object first before assigning properties into it:

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

With that, you can use the object variable name to access the already assigned values.
Best for config.js file.

查看更多
再贱就再见
7楼-- · 2019-08-06 00:43

Now in ES6 you can create lazy cached properties. On first use the property evaluates once to become a normal static property. Result: The second time the math function overhead is skipped.

The magic is in the getter.

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

In the arrow getter this picks up the surrounding lexical scope.

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  
查看更多
登录 后发表回答