How do I assign a conditional variable without mut

2019-05-05 18:21发布

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'

6条回答
时光不老,我们不散
2楼-- · 2019-05-05 18:46

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)
]
查看更多
可以哭但决不认输i
3楼-- · 2019-05-05 18:46

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.

查看更多
放荡不羁爱自由
4楼-- · 2019-05-05 18:58
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 ;)

查看更多
\"骚年 ilove
5楼-- · 2019-05-05 18:59

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.

查看更多
时光不老,我们不散
6楼-- · 2019-05-05 19:02
(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));
})();
查看更多
对你真心纯属浪费
7楼-- · 2019-05-05 19:04

Ternary 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

  1. determining the day period from the hour
  2. assembling the greeting string

By doing this, you avoid

  1. mutation (local reassignment of greeting)
  2. single-branch if statements
  3. 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 !

查看更多
登录 后发表回答