Process strings of operations This was the task (I don't know the exact wordings anymore):


  You get a string with operation as input:
  
  
  if it is a number push it to stack
  if it is "DUP", then duplicate the one one top and push it to the
  stack
  if it is "POP" then remove the one on top
  if it is "+" add the two numbers on top of the stack and replace
  both with the result of the addition
  if it is "-" then minus the two numbers on top (the second minus
  the first) of the stack and replace both with the result of the
  subtraction
  if an error occurs, e.g. not enough numbers to add/subtract/pop,
  then return -1
  


Examples:

Input: "3 DUP 5 - -"
Output: -1

Input: "13 DUP 4 POP 5 DUP + DUP + -"
Output: 7

Input: "5 6 + -"
Output: -1


My approach is quite simple. I differentiate between numbers and operations. If it is a number I simply push it to the stack. Otherwise Ill check what kind of operation it is. If a valid operation is recognized, then the mapped function will be executed.

If an error occurs, e.g. no more numbers in the stack to be popped, invalid operation, etc. it will return -1.

My solution 

function solution(S) {
    if (!S.length) {
        return -1;
    }
    const stack = new Array();
    const push = n =&gt; stack.push(Number(n));
    const pop = () =&gt; {
        if (!stack.length) {
            throw new Error('empty');            
        }
        return stack.pop();
    }
    const duplicate = () =&gt; {
        try {
            const dup = pop();
            push(dup);
            push(dup);            
        } catch(e) {
            throw new Error(e);    
        }
    };
    const add = () =&gt; {
        try {
            const sum1 = pop();
            const sum2 = pop();
            push(sum1 + sum2);            
        } catch(e) {
            throw new Error(e);    
        }
    };
    const minus = () =&gt; {
        try {
            const min1 = pop();
            const min2 = pop();
            push(min1 - min2);
        } catch(e) {
            throw new Error(e);    
        }
    };
    const ops = {
        "DUP": duplicate,
        "POP": pop,
        "+": add,
        "-": minus,
    };

    const input = S.split(' ');
    input.forEach(x =&gt; {
        if (!isNaN(x)) {
            push(x);
        } else {
            try {
                const sanitzedX = x.toUpperCase();
                if (!ops[sanitzedX]) {
                    return -1;
                }
                ops[sanitzedX]();
            } catch(e) {
                return -1;
            }
        }
    });
    try {
        return pop();
    } catch(e) {
        return -1;
    }
}

console.log(solution("3 DUP 5 - -"));
console.log(solution("13 DUP 4 POP 5 DUP + DUP + -"));
console.log(solution("5 6 + -"));
const stack = new Array()


Use the literal notation ([]) instead. Here's an answer on Stack Overflow that elaborates why you should do that instead of new Array().

const duplicate = () =&gt; {
    try {
        const dup = pop();
        push(dup);
        push(dup);            
    } catch(e) {
        throw new Error(e);    
    }
};


The rule of thumb when it comes to using exceptions is to never use them where you can use an if. That is, don't use exceptions as a flow control mechanism. You should only use it if you want to bail out and do no further.

Also, e is already an instance of Error. You only need to do throw e, not throw new Error(e).

Now if you look closely, all the operations are distinct to each other. They also only operate on the stack only. You can easily implement them as pure functions, taking in the current stack, and returning a new representation of the stack.

For example, duplicate can be implemented as a function that takes an array, and returns a new array, with the last item repeated once more:

const duplicate = stack =&gt;
  stack.length &lt; 1 ? -1 
  : [...stack, stack[stack.length - 1]]


add can be implemented as a function that takes an array, and return an new array which replaces the last two items with their sum:

const add = stack =&gt;
  stack.length &lt; 2 ? -1 
  : [...stack.slice(0, -2), stack[stack.length - 1] + stack[stack.length - 2]]


Doing it this way makes it easier to implement each operation without having them becoming dependent on some common state object, or each other.

Here's how I would implement it:



// Implement each operation as distinct, pure functions.
const push = (stack, v) =&gt; [...stack, v]

const pop = stack =&gt; 
  stack.length &lt; 1 ? -1
  : stack.slice(0, -1)

const duplicate = stack =&gt;
  stack.length &lt; 1 ? -1 
  : [...stack, stack[stack.length - 1]]

const add = stack =&gt;
  stack.length &lt; 2 ? -1 
  : [...stack.slice(0, -2), stack[stack.length - 1] + stack[stack.length - 2]]

const subtract = stack =&gt;
  stack.length &lt; 2 ? -1
  : [...stack.slice(0, -2), stack[stack.length - 1] - stack[stack.length - 2]]

// Map operation tokens to their implementation.
// Should we add more operations, we simply add the implementation and reference
// its token in this map
const operations = {
  'DUP': duplicate,
  'POP': pop,
  '+': add,
  '-': subtract
}

const solution = s =&gt; {

  // For each token, parse and process.
  // You can implement this piece using iteration functions, loops, or even recursion.
  // I'm just more accustomed to reduce because it can carry a value across iterations
  // which, in this case, holds the stack for me.
  const result = s.split(' ').reduce((stack, token) =&gt; {
  
    // If any operation returned -1, we return -1 all the way.
    return stack === -1 ? -1
      // If token is a number, push it to the stack.
      : !isNaN(parseFloat(token)) &amp;&amp; isFinite(token) ? push(stack, Number(token))
      // If token is an operation, apply operation.
      : operations[token.toUpperCase()] ? operations[token.toUpperCase()](stack)
      // Unknown token.
      : -1

  // Our stack as initial reduce value, an empty array.
  }, [])

  // If the result is -1, then so be it. Otherwise, return the top of the stack.
  return result === -1 ? -1 : result[result.length - 1]
}

console.log(solution("3 DUP 5 - -"));
console.log(solution("13 DUP 4 POP 5 DUP + DUP + -"));
console.log(solution("5 6 + -"));