I am adhering to strict functional programming principles with no mutation.
How can I write something like the below code in a way that doesn't mutate the greeting
variable, and without returning it within each if
block?
const greet = (name, time) => {
let greeting = 'Morning';
if(time >= 12) {
greeting = 'Afternoon';
}
if(time >= 17) {
greeting = 'Evening';
}
return `Good ${greeting} ${name}!`;
};
If it was just two conditions I would do the following, but it won't work when there are 3 conditions:
const greeting = time > 12 ? 'Afternoon' : 'Morning'
I am adhering to strict functional programming principles with no mutation.
How can I write something like the below code in a way that doesn't mutate the greeting
variable, and without returning it within each if
block?
const greet = (name, time) => {
let greeting = 'Morning';
if(time >= 12) {
greeting = 'Afternoon';
}
if(time >= 17) {
greeting = 'Evening';
}
return `Good ${greeting} ${name}!`;
};
If it was just two conditions I would do the following, but it won't work when there are 3 conditions:
const greeting = time > 12 ? 'Afternoon' : 'Morning'
Share
Improve this question
asked Jul 26, 2017 at 17:49
Jim MoodyJim Moody
8082 gold badges7 silver badges19 bronze badges
6 Answers
Reset to default 11Ternary expressions can be made up other ternary expressions – allowing us to sequence logical choices
const greeting = time > 12 ? (time > 17 ? 'Evening' : 'Afternoon') : 'Morning'
However, I think it's the variable that makes the variable a variable...
You have two concerns though, and it it will benefit you to separate them
- determining the day period from the hour
- assembling the greeting string
By doing this, you avoid
- mutation (local reassignment of
greeting
) - single-branch if statements
- imperative-style statements altogether (ie
let
,if
,return
,x = ...
)
The result is two pure (referentially transparent) functions written using expressions – there is no assignment (or reassignment), and there are no side-effects.
const timeToPeriod = time =>
time >= 17
? 'Evening'
: time >= 12
? 'Afternoon'
: 'Morning'
const greet = (name, time) =>
`Good ${timeToPeriod(time)} ${name} !`
console.log(greet('Jonas', 9)) // Good Morning Jonas !
console.log(greet('Jonas', 13)) // Good Afternoon Jonas !
console.log(greet('Jonas', 22)) // Good Evening Jonas !
const greeting = [
'Morning', 'Morning', 'Morning', 'Morning', 'Morning', 'Morning', 'Morning',
'Morning', 'Morning', 'Morning', 'Morning', 'Morning',
'Afternoon', 'Afternoon', 'Afternoon', 'Afternoon', 'Afternoon',
'Evening', 'Evening', 'Evening', 'Evening', 'Evening', 'Evening', 'Evening'
]
return `Good ${greeting[time]} ${name}!`
This technically gives you the flexibility to add more times of day in the future, such as adding 'Noon'
on the 12th hour. Additionally, it makes localization easier for similar reasons; Some locales may have a Noon
others may not.
This was originally a joke ;)
This question is already answered but, if you have more than 3 options you could do this:
['Evening', 'Afternoon', 'Morning']
[
[17,12,0].findIndex((el) => time >= el)
]
(function (){
const greet = (name, time) => {
const greetings = [ // Order is important
{greeting: 'Evening',time: 17},
{greeting: 'Afternoon',time: 12},
{greeting: 'Morning',time: -Infinity}
];
const greeting = greetings.find(e=>time>=e.time).greeting;
return `Good ${greeting} ${name}!`;
}
console.log(greet('Me',17));
})();
To be clear you are not doing any mutation, you are using let instead of const. Why it is not a mutation - because string is immutable in javascript. So your question is more - "How assign conditional value to const".
To be clear I don't see anything wrong with doing let here and such behavior. Until this not goes outside the function scope it is just fine to mutate it (I am talking more about general approach, for example with objects).
Immutability rule should be used for structures declared outside the scope of the function. What directly means that you should never mutate function input and never touch what not belongs to you.
To the point, my answer is - leave it as it is, for me it is much more clear than ternary operator with many conditions.
In JavaScript variables by nature cannot be made immutable. But, you can have immutable expressions, either by using a string value or by declaring a constant. This solution relies on three constants. One constant is an object containing string values corresponding to the three periods in a 24-hour time span. The second constant holds the result of testing for the time of day (tod). And, the last constant holds a function expression, i.e. an anonymous function, as follows:
let d = new Date();
let time = d.getHours();
const greeting = {
"morn": "morning",
"after": "afternoon",
"evg": "evening"
};
const greet = function(strName) {
const tod = (time < 12) ? greeting["morn"] :
(time > 17) ? greeting["evg"] : greeting["after"];
let salutation = "Good " + tod;
salutation += ",";
strName += "!";
// adding another functional programming touch
return function() {
console.log([salutation, strName].join(" "));
};
};
var user = "Zander";
greet(user)();
Note that whereas a string value is immutable, the String object itself is mutable. You may add a property to that object and you may change the value of that property; see example here.
The use of keyword const creates a constant and as per MDN:
The value of a constant cannot change through re-assignment, and it can't be redeclared.
In this and the other examples where a constant is set according to the time of day vis a vis a ternary expression, the constant itself is "variable" to the extent that its value varies depending on the time of day that the script runs.