How to pass switch statement as function argument in Javascript ES6?

How to pass switch statement as function argument in javascript?

I want to do this using the Redux library:

const agendaPointsReducer = function (state = initialState, action) { return Object.assign({}, state, switch (action.type) { case OPEN_AGENDA_POINT: { state.modal_is_open = true, state.point_id = action.id } case CLOSE_AGENDA_POINT: { state.modal_is_open = false } }) } 

But I get an unexpected token error. I know this is possible in Coffeescript, is there a way to do this in Javascript es6?

0
source share
6 answers

I think you really want to do something like this:

 const agendaPointsReducer = function (state = initialState, action) { switch (action.type) { case OPEN_AGENDA_POINT: { return { ...state, modal_is_open: true, point_id: action.id }; } case CLOSE_AGENDA_POINT: { return { ...state, modal_is_open: false, }; } } } 
+1
source

One possibility is to turn it into such a function:

 const agendaPointsReducer = function (state = initialState, action) { return Object.assign({}, state, (() => { switch (action.type) { case OPEN_AGENDA_POINT: { state.modal_is_open = true, state.point_id = action.id } case CLOSE_AGENDA_POINT: { state.modal_is_open = false } } })()) } 
+3
source
Operators

switch are not Javascript expressions. In Coffeescript, everything is an expression (a la Ruby). Because of this, there is no way to do this. Also, there is no reason in the example you just indicated, since your switch simply modifies the state variable that is already passed.

+2
source

So, Object.assign() copies the properties of the objects passed to them on the target object. So what you need to pass are objects with properties that it can copy.

If you are trying to create an object that has a property based on the current execution of the switch statement (this is my hunch about what you are trying to do), then I suggest you just create the source object before calling Object.assign() and pass that object to it.

By doing this, as I will show here, you will avoid any side effects that could change the one passed in the object too (why do we set the properties in the switch statement on the local object, and not on the state object):

 const agendaPointsReducer = function (state = initialState, action) { let srcObj = {}; switch (action.type) { case OPEN_AGENDA_POINT: srcObj.modal_is_open = true; srcObj.point_id = action.id; break; case CLOSE_AGENDA_POINT: srcObj.modal_is_open = false; break; } return Object.assign({}, state, srcObj); } 
+1
source

In addition to these answers specific to your question, I want to provide you with a more general answer.

Pass the switch function you want to convert to an expression. There are two different ways to achieve this.

Switch switch in function

 const apply = f => x => f(x); const enumerate = apply(x => { switch (x.constructor) { case Number: { return inc(x); } case String: { return succ(x); } default: throw TypeError(); } }); const inc = x => x + 1; const succ = x => String.fromCharCode(x.charCodeAt(0) + 1); console.log("enum 1:", enumerate(1)); // 2 console.log("enum a:", enumerate("a")); // "b" 

With this approach, I use apply as a helper function. This makes the calling code more readable, for example. Object.assign({}, state, apply(x => {/* switch statement */}) (action.type))

Express switch in itself as a function

 const caseOf = (...pairs) => x => { let g; pairs.some(([guard, f], i) => guard(x) ? (g = f, true) : false); return g(x); } const inc = x => x + 1; const succ = x => String.fromCharCode(x.charCodeAt(0) + 1); const enumerate = caseOf( [x => x.constructor === Number, x => x + 1], [x => x.constructor === String, x => String.fromCharCode(x.charCodeAt(0) + 1)] ); console.log("enum 1:", enumerate(1)); console.log("enum a:", enumerate("a")); 

caseOf is a normal function, a higher function of a higher order. You can apply it wherever an expression is allowed.

Destruction Assignment

The purpose of destructuring is the non-obvious advantage that both approaches have more normal switch . You can apply the destructuring assignment without additional variables:

 const apply = f => x => f(x); const sqr = x => x * x const xs = [2], ys = []; console.log( sqr(apply(([x]) => { // <= destructuring assignment switch (x) { case undefined: return 0; default: return x; } }) (xs)) ); console.log( sqr(apply(([x]) => { // <= destructuring assignment switch (x) { case undefined: return 0; default: return x; } }) (ys)) ); 

 const caseOf = (...pairs) => x => { let g; pairs.some(([guard, f], i) => guard(x) ? (g = f, true) : false); return g(x); } const sqr = x => x * x; const isAssigned = x => x !== undefined && x !== null; const always = x => _ => x; const xs = [5], ys = []; console.log( caseOf( [([x]) => isAssigned(x), sqr], // <= destructuring assignment [always(true), always(0)] // default case ) (xs) ); console.log( caseOf( [([x]) => isAssigned(x), sqr], // <= destructuring assignment [always(true), always(0)] // default case ) (ys) ); 

I hope this helps.

+1
source

I think the answers given by daniel_franz and jfriend00 are the best and easiest solutions. But it's still interesting to think about alternatives :)

I was interested in experimenting with trying to save switch logic in a Map . It probably has a lot of flaws (for example, you cannot catch cases by omitting break ), and this makes things too complicated, so I think we will have to consider this as just a study, and not like "so I would do it in a real project "...

An approach:

  • Create a Map for each case record
  • Each entry has a case as a key.
  • Each entry has a function that returns the desired result as a value.
  • For cases of undefined Map getItem returns null , which we will also wrap with a function

Code:

 const apply = f => typeof f === "function" ? f() : null; const Switch = (input, ...entries) => apply(new Map(entries).get(input)); const types = { INCREMENT: "INCREMENT", DECREMENT: "DECREMENT", SQUARE: "SQUARE" }; const myNumberReducer = function(state = { myNumber: 0 }, action = {}) { return Object.assign({}, state, Switch(action.type, [ types.INCREMENT, () => ({ myNumber: state.myNumber + 1 }) ], [ types.DECREMENT, () => ({ myNumber: state.myNumber - 1 }) ], [ types.SQUARE, () => ({ myNumber: state.myNumber * state.myNumber }) ] )); } let lastState = myNumberReducer(); console.log(lastState); // myNumber: 0 lastState = myNumberReducer(lastState, { type: types.INCREMENT }); console.log(lastState); // myNumber: 1 lastState = myNumberReducer(lastState, { type: types.INCREMENT }); lastState = myNumberReducer(lastState, { type: types.SQUARE }); console.log(lastState); // myNumber: 4 
+1
source

Source: https://habr.com/ru/post/1264770/


All Articles