2016-11-01 4 views
1

Я пытаюсь создать простой калькулятор JavaScript. Тем не менее, когда я запускаю мой код и внести изменения в любой из трех полей (значение коробки или знака), я получаю сообщение об ошибке с указаниемПроблемы с закрытием и ключевым словом «this» в JavaScript

this.calculate не является функцией

ошибка приходит вверх в соответствии с этим. Калькуляция для любой функции прототипа вызывается в зависимости от того, измените ли вы свое числовое значение или знак формулы.

Я читал о закрытии, обратном вызове и ключевом слове «это», и я считаю, что проблема там где-то там, где я называю свои прототипы. Кто-нибудь поможет объяснить, где в моем коде я делаю ошибку и как ее решить?

Вот JavaScript

var Formula=function() { 
    this.value1 = null; 
    this.value2 = null; 
    this.sign = null; 
    this.result = null; 
}; 

Formula.prototype.calculate = function() { 
    switch (this.sign) { 
    case '+': 
     this.result = this.value1 + this.value2; 
     break; 
    case '-': 
     this.result = this.value1 - this.value2; 
     break; 
    case '/': 
     this.result = this.value1/this.value2; 
     break; 
    case '*': 
     this.result = this.value1 * this.value2; 
     break; 

    default: 
     break; 
    } 
    document.querySelector('#result').innerHTML = this.result; 
}; 

Formula.prototype.updateValue = function(event) { 
    if (event.currentTarget.id === '#value1') 
     this.value1 = parseFloat(event.currentTarget.value); 
    else this.value2 = parseFloat(event.currentTarget.value); 
    this.calculate(); 
}; 

Formula.prototype.updateSign = function(event) { 
    this.sign = event.currentTarget.value; 
    this.calculate(); 
}; 

document.addEventListener('DOMContentLoaded', function() { 
(function() { 
    var equation = new Formula(); 
    document.querySelector('#sign').addEventListener('change', equation.updateSign); 
    var values = document.querySelectorAll('.value'); 
    for (var i = 0, numValues = values.length; i < numValues; i++) { 
     values[i].addEventListener('change', equation.updateValue); 
    } 
})(); 
}); 

А вот HTML

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="UTF-8"> 
<script type="text/javascript" src="calcJS.js"></script> 
</head> 
<body> 
<input type="number" class="value" id="value1"/> 
<select id="sign"> 
    <option value="+">+</option> 
    <option value="-">-</option> 
    <option value="*">*</option> 
    <option value="/">/</option> 
</select> 
<input type="number" class="value" id="value2"/> 
= 
<span id="result"/> 
</body> 
</html> 
+3

Привет, Пожалуйста, не теряйте свой пост после того, как вы воспользовались им. Это похоже на вырубку дерева после укрытия под ним. Пожалуйста, позвольте другим будущим пользователям получить знания. Ответчики приложили бы немало усилий. Не тратьте свое драгоценное время впустую. –

+0

Извините, я пытался переделать код и внести изменения и задать другой вопрос, вместо этого сделать еще одну запись. – sota7green

+0

@ sota7green не делайте этого либо xD Если у вас есть другой вопрос, * задайте другой вопрос *, не редактируйте текущий. –

ответ

1

Значение this в функции зависит от того, как называется функция.

Обычно, когда вы

var equation = new Formula(); 

equation.updateSign(); 

this бы "Формула объект" внутри updateSign

Однако, когда вы делаете это

var equation = new Formula(); 
document.querySelector('#sign').addEventListener('change', equation.updateSign); 

вы ссылающийся на функцию, а не вызывающий его, обработчик события в конечном итоге вызывает его, установив значение this на измененный элемент, а не equation объект

Если вы хотите this быть объект вместо этого, вы должны были бы сделать что-то вроде

var equation = new Formula(); 
document.querySelector('#sign').addEventListener('change', function() { 
    equation.updateSign(arguments); 
}); 

или с помощью привязки вернуть новую функцию с набором this значение,

var equation = new Formula(); 
document.querySelector('#sign').addEventListener('change', equation.updateSign.bind(equation)); 

FIDDLE

У вас также был логический недостаток

if (event.currentTarget.id === '#value1') 

Идентификатор всегда возвращается без хэш

if (event.currentTarget.id === 'value1') 
+0

Большое вам спасибо, я читал на bind/apply и пытался обернуть вокруг себя голову, но ваше объяснение заставил ее щелкнуть! По какой-то причине фактическое уравнение не печатает правильные результаты для меня, когда я вытягиваю HTML в браузере, но он работает на вашей скрипке. Вы знаете, почему это так? – sota7green

+0

@ sota7green - я исправил небольшую ошибку с возвращенным ID, чтобы заставить скрипку работать, но забыл добавить это в ответ. – adeneo

+0

Есть ли способ, чтобы уравнение выполнялось, как только заполнялись оба поля значений? Например, я ввожу 3 и 4 в ящики без изменения знака «+» по умолчанию и запускаю ли его сразу, не меняя знак оператора? – sota7green

0

вопрос, который вы видите, это связано с тем, как это событие обработки работ. Когда вызывается обработчик событий, this неявно передается функции обработчика как элемент, который является объектом события.

Чтобы сохранить исходную область this, вам необходимо обернуть свою функцию и вызвать ее напрямую.Например:

var equation = new Formula(); 

document.querySelector('#sign').addEventListener('change', function(event) 
{ 
    equation.updateSign(event); 
}); 

Это Fiddle помогает проиллюстрировать. Надеюсь, это поможет.

+0

Спасибо! Это решило проблему. Когда я ввожу свои значения по какой-то причине, результаты неверны. Кажется, что распечатывает только первое число и делает его положительным или отрицательным в зависимости от знака. Что-то не так с моей функцией .calculate? – sota7green

+0

Похоже, адэней уже поймал здесь ошибку, которую он назвал логическим недостатком в своем ответе. –