; PSY 1903
PSY 1903 Programming for Psychologists

Conditionals and Refactoring

Conditionals

Building on what we learned about Boolean expressions, we can start to work with conditionals. Conditionals allow us to make our code more dynamic because we can vary what lines of code are executed based on different conditions. For example:

let response = prompt('What is 4 + 6?');

if (response == 10) {
    alert('Correct!');
}

The above code uses an if condition. Following the keyword if is a Boolean expression (response == 10). If this expression evaluates to True, any code that follows within the curly brackets {} will be executed.

Note how the code within the curly brackets is indented. The indentation isn’t necessary but is considered best practice because it makes it visually clear the contents are within the body of the if condition.

If/Else

To have an alternative message print if the user got the answer incorrect, we can introduce an else condition.

let response = prompt('What is 4 + 6?');

if (response == 10) {
    alert('Correct!');
} else {
    alert('Incorrect.');
}

Chained conditions

You can chain together if conditions using the else if keyword:

let response = prompt('What is 4 + 6?');

if (response == 10) {
    alert('Correct!');
} else if (response >= 8 && response <= 12) {
    alert('Close! The answer is 10.');
} else {
    alert('Incorrect. The answer is 10.');
}

Another example with multiple else ifs:

let response = prompt('What is 4 + 6?');

if(response == 10) {
    alert('Correct! The answer is 10.');
} else if(response == 9 || response == 11) {
    alert('Very close! The answer is 10.');
} else if(response == 8 || response == 12) {
    alert('Close! The answer is 10.');
} else {
    alert('Incorrect. The answer is 10.');
}

Note that with chained if/else if blocks that once one of the conditions is met, the remainder of the blocks will not be executed.

Refactoring (improving our code)

In the above code, we have the String 'The answer is 10.' repeated 4 times in our code. This doesn’t mean that String will actually be printed 4 times to the user, because we know that only one of the branches of the if/else if condition will be executed, but it does introduce redundancy in our code.

This redundancy breaks a rule programmers like to follow called DRY - Don’t Repeat Yourself. When possible and logical, we like to reduce redundancy in programs because it can make the code easier to maintain.

For example, imagine we wanted to change the language of 'The answer is 10' to simply 'Answer: 10'. As we’ve written the code so far, we’d have to make that change in 4 different places, and if this were a larger more complex example, it’s possible we might miss a place where it needed to change.

There’s a couple different ways we could optimize this. First, we could centralize the language by storing it in a variable:

let response = prompt('What is 4 + 6?');

// ⭐ Centralize the answer language by storing it in a variable
let correctAnswer = 'The answer is 10';

if (response == 10) {
    alert('Correct! ' + correctAnswer);
} else if (response == 9 || response == 11) {
    alert('Very close! ' + correctAnswer);
} else if (response == 8 || response == 12) {
    alert('Close! ' + correctAnswer);
} else {
    alert('Incorrect ' + correctAnswer);
}

Now, if we wanted to update the language of 'The answer is 10' to 'Answer: 10', we would only have to make that change in one place by updating our answerLanguage variable. This is a nice improvement, and in many situation creating variables to manage repeat data is a good approach.

There’s still some unnecessary redundancy though because answerLanguage is going to be printed regardless of which branch of our if/else block is executed. Knowing that, why not just put it as it’s own independent print statement after the if/else block?

let response = prompt('What is 4 + 6?');

if (response == 10) {
    alert('Correct!');
} else if (response == 9 || response == 11) {
    alert('Very close!');
} else if (response => 8 || response <= 12) {
    alert('Close!');
} else {
    alert('Incorrect');
}

// ⭐ Print the answer outside the if/else if/else block 
// since it needs to print no matter the outcome
alert('The answer is 10');

Or, we could do something like this:

let response = prompt('What is 4 + 6?');

// Initialize a feedback variable that will be 
// updated based on the condition met below
let feedback = '';

if (response == 10) {
    feedback = 'Correct!';
} else if (response == 9 || response == 11) {
    feedback = 'Very close!';
} else if (response == 8 || response == 12) {
    feedback = 'Close!';
} else {
    feedback = 'Incorrect';
}

alert(feedback + ' The answer is 10');

Refactoring

The above process of re-writing/tweaking code to optimize how it’s written is referred to as refactoring. The process of refactoring highlights that in coding there is often many ways to solve the same problem.

In some situations, refactoring is done to produce code that operates faster and/or more efficiently. More often, though, refactoring is done just to yield code that is easier to understand and maintain.

So keep this in mind as you write code - it's an iterative process, and you should occasionally pause and rewind on your code to see if there’s a cleaner or more efficient approach you could have taken.

Another helpful use of refactoring is to do it whenever you’re stuck on a problem. Sometimes the process of just going back through your code to clean it up or review what you’ve done can point you in the direction of a mistake.