9

Самоссылки в объектных литералах / инициализаторах

8

Вопрос о зависимостях свойств в объекте JavaScript

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

var foo = {
    a: 5,
    b: 6,
    c: this.a + this.b  // Не работает
};

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

5 ответ(ов)

3

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

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

Это будет неким однократным инициализацией объекта.

Обратите внимание, что вы фактически присваиваете результат выполнения функции init() переменной foo, поэтому вам нужно вернуть this.

0

Чтобы создать анонимную функцию, просто инстанцируйте её следующим образом:

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

В этом примере создается новый объект, и свойства a, b и c устанавливаются на его основе. Переменная foo будет содержать объект с этими свойствами. Обратите внимание, что this внутри анонимной функции ссылается на экземпляр объекта, который вы создаете с помощью new. Таким образом, foo.c будет равно 11 (5 + 6).

0

Некоторые замыкания должны это обработать.

var foo = function() {
    var a = 5;
    var b = 6;
    var c = a + b;

    return {
        a: a,
        b: b,
        c: c
    }
}();

Все переменные, объявленные внутри foo, являются приватными для этой функции, как вы и ожидаете от любого объявления функции. Поскольку все они находятся в области видимости, они могут обращаться друг к другу без необходимости использовать this, как это и должно быть в функции. Разница заключается в том, что эта функция возвращает объект, который открывает доступ к приватным переменным и присваивает этот объект переменной foo. В конечном итоге вы возвращаете только интерфейс, который хотите предоставить, используя оператор return {}.

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

0

Вы можете сделать это следующим образом:

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 как объект, который содержит функцию log, вы позволяете функции обращаться к этому объекту. Это означает, что вам не придется «привязывать» функцию log к объекту, если вам нужно будет передать её куда-то ещё.

Если бы вы вместо этого использовали 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 ссылается на объект o.a, так что цепочка работает
log().log() // this ссылается на объект window, так что цепочка рушится!

Используя метод с self, вы гарантируете, что функция log всегда будет возвращать один и тот же объект независимо от контекста, в котором она вызывается. Код выше будет работать исправно и выведет 0, 1, 2 и 3 при использовании версии createMyObject() с self.

0

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

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

const foo = new Foo();

В данном примере создается класс Foo, который имеет конструктор, инициализирующий два свойства a и b, а также вычисляющий сумму этих свойств и сохраняющую ее в c. Создавая новый экземпляр этого класса с помощью new Foo(), мы получаем объект foo, который будет содержать эти значения.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь