Самостоятельные ссылки в объектных литералах / инициализаторах - PullRequest
613 голосов
/ 06 января 2011

Есть ли способ заставить что-то вроде следующего работать в JavaScript?

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

В текущей форме этот код явно выдает ошибку ссылки, так как this не ссылается на foo.Но - это , есть ли способ, чтобы значения в свойствах литерала объекта зависели от других объявленных ранее свойств?

Ответы [ 23 ]

6 голосов
/ 11 августа 2015

просто ради мысли - разместите свойства объекта вне временной шкалы:

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

console.log(foo.c())

выше есть и лучшие ответы . Вот как я изменил пример кода, который вы опрашивали.

UPDATE:

var foo = {
    get a(){return 5},
    get b(){return 6},
    get c(){return this.a + this.b}
}
// console.log(foo.c);
4 голосов
/ 07 мая 2014

Ключом ко всему этому является SCOPE .

Вам необходимо инкапсулировать "parent" (родительский объект) свойства, которое вы хотите определить, как его собственный экземплярный объект, а затемВы можете делать ссылки на свойства одного и того же брака, используя ключевое слово 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)
};
4 голосов
/ 14 сентября 2014

Создание новой функции на вашем литерале объекта и вызов конструктора кажется радикальным отходом от исходной проблемы, и в этом нет необходимости.

Вы не можете ссылаться на одноуровневое свойство во время инициализации литерала объекта.

var x = { a: 1, b: 2, c: a + b } // not defined 
var y = { a: 1, b: 2, c: y.a + y.b } // not defined 

Ниже приводится простейшее решение для вычисляемых свойств (без кучи, без функций, без конструктора):

var x = { a: 1, b: 2 };

x.c = x.a + x.b; // apply computed property
2 голосов
/ 13 июня 2018

Вот изящный способ 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]);
2 голосов
/ 13 августа 2016

, если ваш объект написан как функция, которая возвращает объект, И вы используете объектный атрибут 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);
2 голосов
/ 25 марта 2015

Другие ответы, опубликованные здесь, лучше, но вот альтернатива:

  • Устанавливает значение при инициализации (не получатель, или производный, и т. Д.)
  • Не требует какого-либо типа init() или кода вне литерала объекта
  • Является литералом объекта, а не фабричной функцией или другой механикой создания объекта.
  • Не должно влиять на производительность (кроме как при инициализации)

Самовыполняющиеся анонимные функции и хранилище окон

var foo = {
    bar:(function(){
        window.temp = "qwert";
        return window.temp;
    })(),
    baz: window.temp
};

Заказ гарантированный (bar до baz).

Конечно, это загрязняет window, но я не могу представить, чтобы кто-то писал сценарий, который требует window.temp, чтобы быть стойким. Может быть tempMyApp, если вы параноик.

Это также безобразно, но иногда полезно. Например, когда вы используете API с жесткими условиями инициализации и не чувствуете необходимость рефакторинга, поэтому область видимости верна.

И сухо, конечно.

1 голос
/ 09 июня 2019

Другой подход заключается в том, чтобы сначала объявить объект, прежде чем присваивать ему свойства:

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 файл.

1 голос
/ 21 ноября 2016

Как насчет этого решения, это также будет работать с вложенными объектами с массивом

1 голос
/ 17 июня 2016

Я использую следующий код в качестве альтернативы, и он работает. И переменная тоже может быть массивом. (@ 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]
0 голосов
/ 27 апреля 2019

Если вы хотите использовать нативный JS, другие ответы дают хорошие решения.

Но если вы предпочитаете писать объекты, ссылающиеся на себя, например:

{ 
  a: ...,
  b: "${this.a + this.a}",
}

Я написалБиблиотека npm с именем self-referenced-object , которая поддерживает этот синтаксис и возвращает собственный объект.

...