Самоссылки в объектных литералах / инициализаторах
Вопрос о зависимостях свойств в объекте 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, имея её имя в виде строки
В чем разница между String.slice и String.substring?
Проверка соответствия строки регулярному выражению в JS