get and set - garevna/js-course GitHub Wiki
:mortar_board: Вычисляемые свойства
У объекта могут быть свойства, значения которых вычисляются на основании значений других свойств
:coffee: :one:
Предположим, есть объект commodity, описывающий товар
Цена товара priceUSD установлена в долларах
Предположим, курс доллара устанавливается значением переменной course
Для получения цены товара в гривне нужно умножить цену товара в долларах на курс доллара
Однако крайне неудобно производить подобные операции каждый раз, когда нужна цена товара в гривне
Создадим вычисляемое свойство priceUAH
Для этого объявим геттер и сеттер свойства
var course = 28
var commodity = {
name: "Утюг",
mark: "Tefal",
priceUSD: 20,
get priceUAH () {
return this.priceUSD * course
},
set priceUAH ( newPriceUAH ) {
this.priceUSD = newPriceUAH / course
}
}
Геттер - это функция, которая будет вычислять актуальное значение цены товара в гривне и возвращать результат как значение свойства commodity.priceUAH
:warning: У геттера не может быть аргументов
Сеттер - это функция, которая будет получать новое значение цены товара в гривне ( newPriceUAH ) и пересчитывать цену товара в долларах ( commodity.priceUSD ) по текущему курсу ( course )
Каждый раз, когда мы будем обращаться к свойству commodity.priceUAH,
console.log ( commodity.priceUAH )
будет срабатывать геттер
Результат:
560
Каждый раз, когда мы будем присваивать новое значение свойству commodity.priceUAH, на самом деле будет вызываться функция-сеттер, которая будет изменять значение свойства commodity.priceUSD
commodity.priceUAH = 250
console.log ( commodity.priceUSD )
Результат:
8.928571428571429
Для вычисляемых свойств "под капотом" операция присваивания заменяется вызовом функции-сеттера
:warning: Поэтому категорически нельзя внутри функции-сеттера использовать присваивание значения этому же свойству:
:no_entry_sign:
var commodity = {
name: "Утюг",
mark: "Tefal",
priceUSD: 20,
get priceUAH () {
return this.priceUSD * course
},
set priceUAH ( newPriceUAH ) {
this.priceUAH = newPriceUAH
}
}
Это приведет к бесконечной рекурсии и генерации исключения:
❌ ► Uncaught RangeError: Maximum call stack size exceeded
:coffee: :two:
Создадим простенький объект-калькулятор:
var calculator = {
firstValue: 0,
secondValue: 0,
operations: [ "+", "-", "*", "/", "%" ],
operation: "+",
get result () {
return eval( `${this.firstValue}${this.operation}${this.secondValue}` )
},
set result ( newValue ) {
for ( var x of this.operations ) {
let vars = newValue.split ( x )
if ( vars.length === 1 ) continue
this.operation = x
this.firstValue = Number ( vars[0] )
this.secondValue = Number ( vars[1] )
break
}
}
}
Вычисляемое свойство result этого объекта имеет геттер и сеттер
Когда мы обращамся к свойству result для получения его значения, срабатывает геттер
console.log ( calculator.result )
Если же мы выполним присваивание нового значения свойству result
calculator.result = "5 - 8 "
сработает сеттер свойства, и в результате будут изменены значения свойств firstValue, secondValue и operation объекта calculator
▼ {firstValue: 5, secondValue: 8, operations: Array(5), operation: "-"}
firstValue: 5
operation: "-"
► operations: (5) ["+", "-", "*", "/", "%"]
result: (...)
secondValue: 8
► get result: ƒ result()
► set result: ƒ result( newValue )
► __proto__: Object
:coffee: :three:
Создадим вычисляемое свойство state объекта human
var human = {
name: "Иван Сидоренко",
states: [ "work", "relax", "enjoy" ],
currentState: 0,
get state () {
return this.states [ this.currentState ]
},
set state ( newState ) {
this.states.indexOf ( newState ) < 0 ?
this.states.push ( newState ) : null
this.currentState = this.states.indexOf ( newState )
},
showState: function () {
console.log ( `Current state: ${this.currentState} ( ${this.state} )` )
}
}
human.showState()
Результат:
Current state: 0 ( work )
Если вычисляемое свойство state фигурирует в левой части оператора присваивания, то вызывается сеттер свойства
Сеттер проверяет наличие такого значения в массиве human.states, и если такого значения там нет, то добавляет его
Затем сеттер свойства state устанавливает значение свойства human.currentState равным индексу элемента массива human.states, значение которого будет отображать геттер свойства state
human.state = "swim"
human.showState()
Результат:
Current state: 3 ( swim )