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:26

if your object is written as a function which returns an object, AND you use ES6 object-attribute 'methods', then it's possible:

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);
查看更多
爷、活的狠高调
3楼-- · 2019-08-06 00:27

You could do something like:

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

This would be some kind of one time initialization of the object.

Note that you are actually assigning the return value of init() to foo, therefore you have to return this.

查看更多
你好瞎i
4楼-- · 2019-08-06 00:28

Simply instantiate an anonymous function:

var foo = new function () {
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
};
查看更多
Ridiculous、
5楼-- · 2019-08-06 00:28

I use the following code as alternative, and it works. And the variable can be array too. (@ Fausto R.)

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

  d: [10,20,30],
  e: function(x) {
    this.d.push(x);
    return this.d;
  }
};
foo.c(); // 11
foo.e(40); // foo.d = [10,20,30,40]
查看更多
Luminary・发光体
6楼-- · 2019-08-06 00:30

Note: This solution uses Typescript (you can use the vanilla JS which TS compiles to if needed)

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

Here were using class expressions to get the nested object literal interface we'd want. This is the next best thing IMHO to being able to reference the properties of an object during creation.

Main thing to note is while using this solution, you have exact same interface as you'd have had from an object literal. And the syntax is pretty close to an object literal itself (vs using a function, etc).

Compare the following

Solution I've proposed

class asd {
    def = new class {
        ads= 'asd';
        qwe= this.ads + '123';
    };

Solution if object literals would've sufficed

var asd = {
    def : {
        ads:'asd',
        qwe: this.ads + '123';, //ILLEGAL CODE; just to show ideal scenario
    }
}

Another example

Here in this class, you can combine multiple relative path among themselves, which is not possible with an object literal.

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';
        };
    }
}
查看更多
我欲成王,谁敢阻挡
7楼-- · 2019-08-06 00:34

You can do it using the module pattern. Just like:

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

With this pattern you can instantiate several foo objects according to your need.

http://jsfiddle.net/jPNxY/1/

查看更多
登录 后发表回答