@Manngo спасибо за указание на это. Честно говоря, я бы задал тот же вопрос, что и OP, и использую предложенное мной решение. Не уверен, почему это считается неактуальным. Если у вас есть время, пожалуйста, объясните, чтобы я мог лучше ответить или хотя бы знать, в чем я не прав. Я, к сожалению, не понимаю, почему это не разумное решение.

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

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

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

Ответы на вопрос(21)

Вы могли бы сделать что-то вроде:

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

Это будет своего рода однократная инициализация объекта.

Обратите внимание, что вы фактически присваиваете возвращаемое значениеinit() вfooПоэтому вы должныreturn this.

 Felix Kling26 июл. 2016 г., 21:51
@akantoword: Отлично :), так как объектные литералы - это одно выражение,init() вызов был непосредственно добавлен к литералу, чтобы сохранить его единым выражением. Но, конечно, вы можете вызывать функцию отдельно от того, что хотите.
 Felix Kling01 июн. 2015 г., 05:02
@MuhammadUmer: Не уверен, насколько классы ES6 имеют отношение к этому вопросу.
 T.J. Crowder19 мая 2014 г., 09:30
@BillyMoon: Да, действительно, хотя и делаювлияет на производительность всех последующих обращений к свойствам этого объекта, на многих движках (например, V8).
 Felix Kling01 июн. 2015 г., 05:45
@MuhammadUmer: классы - просто синтаксический сахар для функций конструктора, поэтому они не предоставляют ничего нового. В любом случае, основное внимание в этом вопросе уделяется объектным литералам.
 Billy Moon26 июл. 2011 г., 03:12
Вы также можетеdelete this.init доreturn this так чтоfoo не объявлено

в ES6 у нас есть классы (поддерживаемые на момент написания этой статьи только в последних браузерах, но доступные в Babel, TypeScript и других транспиляторах)

class Foo {
  constructor(){
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
  }  
}

const foo = new Foo();

ассивом, а также

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

Вы могли бы сделать это так

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
            }
        }
    }
}

Определяя себя как объект, который содержит функцию печати, вы позволяете функции ссылаться на этот объект. Это означает, что вам не нужно будет «связывать» функцию печати с объектом, если вам нужно передать его куда-то еще.

Если бы вы вместо этого использовали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().

 user66303106 сент. 2014 г., 19:18
Хорошие примеры, за исключением того, что вы пропустили все точки с запятой.
 Kerem Baydoğan16 янв. 2017 г., 20:44
Нет точек с запятой -Это отлично В самом деле!

рвом использовании свойство оценивается один раз, чтобы стать нормальным статическим свойством. Результат: во второй раз пропускаются служебные данные математической функции.

Магия в добытчике.

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

В стрелке добытчикthis поднимаетокружающая лексическая область.

foo     // {a: 5, b: 6}
foo.c   // 11
foo     // {a: 5, b: 6 , c: 11}  
 Aluan Haddad18 апр. 2017 г., 03:56
es5 также имеет свойства, которые вам просто нужно использоватьObject.defineProperty(foo, 'c', {get:function() {...}}) определить их. Это легко сделать ненавязчивым способом на такой фабрике, как эта. Конечно, если вы можете использоватьget сахар это более читабельно, но возможность была там.

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

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

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

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

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

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

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

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

и он работает. И переменная тоже может быть массивом. (@ Фаусто Р.)

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]

так как я не видел этого точного сценария. если тыне хотеть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

кажется радикальным отходом от исходной проблемы, и в этом нет необходимости.

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

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

Примечание: Это решение использует Typescript (вы можете использовать ванильный JS, к которому TS при необходимости компилируется)

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

Здесь мы использовали выражения класса, чтобы получить литеральный интерфейс вложенного объекта, который нам нужен. ИМХО это следующая лучшая вещь, чтобы иметь возможность ссылаться на свойства объекта во время создания.

Главное, на что нужно обратить внимание, это то, что при использовании этого решения у вас точно такой же интерфейс, какой был бы у литерала объекта. И синтаксис довольно близок к самому литералу объекта (против использования функции и т. Д.).

Сравните следующееРешение, которое я предложил

    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';
        };
    }
}
 Manngo08 июл. 2018 г., 02:44
Может быть потому, что ваш ответ совершенно не имеет значения? Я согласен, что downvoters должны объяснить, но ваш ответ ясно не имеет ничего общего с вопросом ...
 Dheeraj Bhaskar09 июл. 2018 г., 09:18
@Manngo спасибо за указание на это. Честно говоря, я бы задал тот же вопрос, что и OP, и использую предложенное мной решение. Не уверен, почему это считается неактуальным. Если у вас есть время, пожалуйста, объясните, чтобы я мог лучше ответить или хотя бы знать, в чем я не прав. Я, к сожалению, не понимаю, почему это не разумное решение.

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 в соответствии с вашими потребностями.

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

 Rafael Rocha16 янв. 2014 г., 20:48
«Шаблон Module был изначально определен как способ обеспечить как частную, так и публичную инкапсуляцию для классов в традиционной разработке программного обеспечения». Из:Изучение шаблонов дизайна JavaScript, Этот объект следует шаблону модуля, описанному выше, но, возможно, это не лучший способ объяснить это, потому что он не показывает публичные и частные свойства / методы. Вот этотjsfiddle.net/9nnR5/2 это один и тот же объект с общими и частными свойствами / методами. Так что они оба следуют этой схеме
 Hollister26 дек. 2013 г., 02:24
Это не пример шаблона модуля, просто функция. Если последняя строка определения foo была}();, он будет сам исполняться и возвращать объект, а не функцию. Также,foo.c является функцией, поэтому запись в нее прерывает эту функцию и следующий вызов черезfooObject.c() не удастся. Может быть, этоиграть на скрипке ближе к тому, что вы собираетесь (это также синглтон, не предназначенный для реализации).

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

ОБЪЕМ.

Вам необходимо инкапсулировать «родительский» (родительский объект) свойства, которое вы хотите определить как его собственный экземплярный объект, а затем вы можете делать ссылки на свойства-братья, используя ключевое слово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)
};
 Bergi01 авг. 2015 г., 21:27
 user66303106 сент. 2014 г., 19:19
Это даже не действительный JS.

Ноявляется Есть ли способ, чтобы значения в свойствах литерала объекта зависели от других свойств, объявленных ранее?

Нет. Все решения здесь откладывают его до тех пор, пока объект не будет создан (различными способами), а затем присваивают третье свойство.самый простой способ просто сделать это:

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

Все остальные - просто более косвенные способы сделать то же самое. (Феликс особенно умен, но требует создания и уничтожения временной функции, добавления сложности; либо оставляет дополнительное свойство для объекта, либо [если вы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);
 T.J. Crowder05 мая 2018 г., 11:24
@DavidKennell: не становится более официальным, чемспецификация, :-) Ты бы наверное началВот и выполните это до конца. Это довольно странный язык, но в основном вы увидите в различных подпунктахОценка определения недвижимости что объект недоступен операциям, определяющим значения инициализаторов свойств.
 David Kennell05 мая 2018 г., 03:27
Для собственного здравого смысла я пытаюсь найти какую-то официальную документацию, которая говорит в основном то же самое - что объектthis доступно только дляметоды указанного объекта, и никаких других видов свойств. Есть идеи, где я могу найти это? Спасибо!

это то, что я бы использовал:

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
 ken16 янв. 2011 г., 01:16
Правда, извините, я пропустил объектно-буквальный тег изначально. Я в основном использую объектные литералы только для структур данных, и каждый раз, когда мне нужна дополнительная логика (которая может напоминать класс), я создаю объект как результат функции по этой самой причине.
 kpozin15 янв. 2011 г., 18:01
Это работает, но исключает преимущества буквальной нотации объекта.

Просто создайте анонимную функцию:

var foo = new function () {
    this.a = 5;
    this.b = 6;
    this.c = this.a + this.b;
};
 Bergi01 авг. 2015 г., 18:11
 Bergi01 авг. 2015 г., 21:13
@zzzzBov: просто используйтеvar foo = function() { this.…; return this; }.call({}); который синтаксически не сильно отличается, но семантически вменяемый.
 Randy11 мар. 2016 г., 15:58
Вы получили это. Я действительно не заметилnew ключевое слово.
 zzzzBov01 авг. 2015 г., 18:54
@ Берги, почему? Потому что кто-то может создать экземпляр того же объекта из этого? Не то чтобы они не могли просто клонировать объектный литерал. Это ничем не отличается от передачи аргумента, какnew Point(x, y) за исключением того, что функция не названа для повторного использования.
 zzzzBov11 мар. 2016 г., 15:55
@randy, ты явно пропустилnew Ключевое слово было использовано для создания экземпляра функции в качестве экземпляра.foo будет объектом после назначения, а не функцией. Пожалуйста, оцените ваш комментарий и проголосуйте.

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

Так:

объект

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

Объект 2

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

сливаться

Object.assign(foo, foo2);

или же

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

Результат foo:

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

Все в том же JS, нет новых функций в объекте, только с использованием назначить или распространение.

которая возвращает объект, И вы используете объектный атрибут 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);
Решение Вопроса

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

foo.c; // 11

Это синтаксическое расширение, представленное в спецификации ECMAScript 5-го издания, синтаксис поддерживается большинством современных браузеров (включая IE9).

 Randy11 мар. 2016 г., 15:28
@HBP Это было бы точно так же, как то, что произошло бы в вопросе, поэтому мне кажется, что именно так и должен быть ожидаемый результат.
 HBP02 мая 2015 г., 08:21
Остерегайтесь этого с этим решением, если значенияfoo.a или жеfoo.b изменяются тогда значениеfoo.c также изменится синхронно. Это может или не может быть то, что требуется.
 Charlie Martin19 сент. 2014 г., 21:04
@FaustoR. Да.
 jake02 февр. 2013 г., 17:21
Очень полезный ответ. Более подробную информацию о 'get' можно найти здесь:developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/...
 Z. Khullah18 апр. 2018 г., 22:22
Обратите внимание, чтоthis связывается с самым глубоким вложенным объектом. Например.:... x: { get c () { /*this is x, not foo*/ } } ...

лы:

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);
 user99368306 дек. 2016 г., 06:42
В ES6 вы можете сделать этот общий подход гораздо более элегантным:var foo = { get a(){return 5}, get b(){return 6}, get c(){return this.a + this.b} } так что теперь вы можете просто сделатьfoo.c вместоfoo.c() :) (Не стесняйтесь вставить это в свой ответ, чтобы форматирование было лучше!)

Некоторое закрытие должно иметь дело с этим;

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

 user66303106 сент. 2014 г., 19:17
Смущать и вводить в заблуждение называть это «закрытием». Хотя мнения относительно точного значения, возвращающего значение ojbect из функции, не являются закрытием в чьей-либо книге.

Ваш ответ на вопрос