Why does concatenating this string before adding it as a parameter to a recursive function cause stack overflow?

function permToN(charList, returnLen, base) {
  if (base.length === returnLen) {
    console.log(base)
  } else {
    for (let char of charList) {
      base += char
      permToN(charList, returnLen, base)
    }
  }
}

permToN(['a', 'b', 'c'], 2, "");

Hi was brushing up on some algorithms and this baffled me. In the above code the problem errs out with Maximum call Stack size exceeded.

However – if I remove the line base += char and make the recursive function call instead with permToN(charList, returnLen, base + char) concatenating the string inside the function param the function works as intended – no stack overflow I am pretty baffled why that small change causes stack overflow. I think I may not understand how the memory is functioning under the hood ? Would greatly appreciate anyone who can explain difference in performance btwn the functions. Below is the function with the concatenation occurring in the params of the function call which works as intended. The above function causes stack overflow. Do not understand the fundamental difference here. thank you!

function permToN(charList, returnLen, base) {
  if (base.length === returnLen) {
    console.log(base)
  } else {
    for (let char of charList) {
      permToN(charList, returnLen, base + char)
    }
  }
}