Самоссылки в объектных литералах / инициализаторах
Вопрос о зависимостях свойств в объекте JavaScript
Есть ли способ сделать что-то вроде следующего кода в JavaScript?
var foo = {
a: 5,
b: 6,
c: this.a + this.b // Не работает
};
В текущем виде этот код вызывает ошибку ссылки, поскольку this не указывает на foo. Но действительно ли есть способ сделать так, чтобы значения свойств в литерале объекта зависели от других свойств, объявленных ранее?
5 ответ(ов)
Вы можете сделать что-то вроде этого:
var foo = {
a: 5,
b: 6,
init: function() {
this.c = this.a + this.b;
return this;
}
}.init();
Это будет неким однократным инициализацией объекта.
Обратите внимание, что вы фактически присваиваете результат выполнения функции init() переменной foo, поэтому вам нужно вернуть this.
Чтобы создать анонимную функцию, просто инстанцируйте её следующим образом:
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).
Некоторые замыкания должны это обработать.
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().
Вы можете сделать это следующим образом:
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.
Для полноты картины, в 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, который будет содержать эти значения.
Как добавить пару ключ/значение в объект JavaScript?
Как использовать переменную в качестве ключа в объектном литературе JavaScript?
Где найти документацию по форматированию даты в JavaScript?
Как проверить, содержит ли массив строку в TypeScript?
Ссылка и выполнение внешнего JavaScript-файла, размещенного на GitHub