Поставлена задача: написать калькулятор, который включает в себя различные операции (+ - * / ^) с поддержкой цепных методов. Так же должен учитываться приоритет операторов. Пример:
const calculator = new SmartCalculator(2);
const value = calculator
.add(2)
.multiply(2);
console.log(value); // 6
Т.е. нужно возвращать не только ответ, но и this, чтобы учитывать последовательность операторов. Как можно вернуть ответ, чтобы не потерять this?
Как я уже писал в комментарии к вопросу:
Основная идея "цепных методов" в том, что необходимо, чтобы метод возвращал тот же объект, на котором вызван этот метод. То есть метод add должен возвращать не число (или строку, или вообще что угодно), а объект calculator. Тогда при последующем вызове multiply выполнится метод multiply объекта calculator.
class SmartCalculator {
constructor(initialValue) {
this.value = initialValue;
}
add(operand) {
this.value += operand;
return this;
}
multiply(operand) {
this.value *= operand;
return this;
}
}
const calculator = new SmartCalculator(2);
const value = calculator
.add(2)
.multiply(2);
console.log(value); // 6
Однако здесь возникает неоднозначная ситуация. console.log()
в последней строчке выводит не число 6
, а объект, у которого поле value
содержит значение 6
.
Если не принципиально, то можно так и вывести:
console.log(value.value);
Но если принципиально, то я пока вижу одно решение: добавить "завершающий метод", вызов которого будет возвращать результат, а не объект:
class SmartCalculator {
constructor(initialValue) {
this.value = initialValue;
}
add(operand) {
this.value += operand;
return this;
}
multiply(operand) {
this.value *= operand;
return this;
}
get result() {
return this.value;
}
}
const calculator = new SmartCalculator(2);
const value = calculator
.add(2)
.multiply(2)
.result;
console.log(value); // 6
Кстати, ответ здесь будет не 6, а 8, поскольку методы вызываются по-порядку.
Набросал по-быстрому вариант с соблюдением приоритета:
class SmartCalculator {
constructor(initialValue) {
this.value = initialValue.toString();
this.expression = "";
this.valueUsed = false;
}
add(operand) {
this.expression += `${this.useExpOrValue(operand)} + ${operand}`;
return this;
}
multiply(operand) {
this.expression += `${this.useExpOrValue(operand)} * ${operand}`;
return this;
}
useExpOrValue(operand) {
let res = !this.valueUsed ? this.value : "";
this.valueUsed = true;
return res;
}
get result() {
console.log(this.expression);
return eval(this.expression);
}
}
const calculator = new SmartCalculator(2);
const value = calculator
.add(2)
.multiply(2)
.result;
console.log(value); // 6
Однако использовать его я крайне не рекомендую по понятным причинам: во-первых - костыль, во-вторых - eval
.
Примерно так:
const value = calculator
.add(2)
.multiply(2)
.calculate();
Всё до calculate
это сборка выражения с учётом порядка операторов, а сам расчёт делается в calculate();
Можно сделать как-то в таком духе (возведение в степень делать поленился):
class SmartCalculator {
constructor(initValue) {
this.init = initValue;
this.operations = [];
}
get result() {
let rpn = [this.init]; // reverse polish notation
let ops = [];
this.operations.forEach(op => { // сортировочная станция
while (ops.length && (ops[ops.length - 1]).priority < op.priority) {
rpn.push(ops.pop().op);
}
ops.push(op);
rpn.push(op.val);
});
while (ops.length) {
rpn.push(ops.pop().op)
}
let res = [];
rpn.forEach(token => {
if (typeof token === 'function') {
res.push(token(res.pop(), res.pop()));
} else {
res.push(token);
}
});
return res.pop();
}
add(val) {
this.operations.push({
op: (a, b) => a + b,
priority: 2,
val: val
});
return this;
}
substract(val) {
this.operations.push({
op: (a, b) => b - a,
priority: 2,
val: val
})
return this;
}
multiply(val) {
this.operations.push({
op: (a, b) => a * b,
priority: 1,
val: val
})
return this;
}
divide(val) {
this.operations.push({
op: (a, b) => b / a,
priority: 1,
val: val
})
return this;
}
valueOf() {
return this.result;
}
}
const value = new SmartCalculator(2)
.add(2)
.multiply(2);
console.log(value == 6);
console.log(+value);
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Прошу помощи в решении задачиПри написании плагина post-css хотелось бы ввести несколько ключевых слов в правила css, например:
Есть js файл и php файлPHP файл лежит на сервере и будет принимать данные post от js, который нужно чтобы работал в фоновом режиме целыми днями
При нажатие Documentonclick() работает только Button 2, а при нажатие document