Project Euler 5 feedback request. Disclaimer: working solution in the thread

BE AWARE working solution in this post

Questions

Object/2-dimensional array dilemma

Not directly related to working solution, but in earlier versions of code was 2 options:
Use nested array or Use object for {key:value} format.
What logic can be applied when making such decisions?

Naming options

In the code below there is function
getProductOfAllPrimeDivisors
This name refers to the mathematical nature of function.

Alternative would be
generateLoopStep
This name refers to the implementation specifics.

What is the best practice when choosing between these two options.

Terminal condition

In this solution I used for loop with empty terminal condition. I could easily set relevant terminal condition. But I decided not to.
Main reason - I can prove by math definitions that in my case terminal condition isn’t necessary at all.
But I still have a suspicion - maybe it’s not best practice?

Any feedback in general would be appreciated.

//factorial is definitely multiple of numbers from 1 to n
//UNIT 1:factorial(n)
//input: number output: number

const factorial = (num) => { //??? maybe there are built-in functions for factorial, more efficient
  //base case
  if (num === 0 || num === 1) {
      return 1;
  }
  //recursive step
  else {
      return num * factorial(num - 1);
  }
}


//if we factorize(factorial(n)) => can get array of its prime divisors

//we will be searching for smallestMult with loop,
//BUT it will be loop with VERY WIDE  step
//for the test case smallestMult(5) answer is 60, but loop step will be 30(2*3*5)
//for the test case smallestMult(13) answer is 360360, but loop step will be 30030(!!!!!!)

//we know(from experiments/testing) >>> factorial and smallestMult
//have the same prime divisors

//loop step will be >>> product of all prime divisors of factorial
//technically it will be nested loops
//BUT >>> the bigger size of problem >>> the wider will be loop step


//UNIT(2) getProductOFAllPrimeDivisors(n) //alternative func name generateLoopStep
//input: number output: number


const getProductOfAllPrimeDivisors = (num) => {
  
  let result = 1;
  
  const arrayOfDivisors = []; //need product of only one occurance
                                //of each prime divisor
  
  while (num !== 1) {
    
        for (let i = 2; i <= num; i++) {

          if (num % i === 0) {
            num = num / i; //need to reinit.num even if primefactor is a duplicate
            if (arrayOfDivisors.indexOf(i) == -1){
              //accumulating only if its 1st occurance of prime factor
              result *= i;
              arrayOfDivisors.push(i);
            }
              
            break;
          }
        } 
  }

  return result;

}

//unit testing
/*
console.log(getProductOfAllPrimeDivisors(120));//30
console.log(getProductOfAllPrimeDivisors(2520));//210
console.log(getProductOfAllPrimeDivisors(24));//6
console.log(getProductOfAllPrimeDivisors(360360));//30030
*/


//UNIT for solution

function smallestMult(n) {
  
  const loopStep = getProductOfAllPrimeDivisors(factorial(n));
  
  

  for (let i = loopStep;;i+=loopStep) { //can set terminal condition but from math standpoint it makes no sense
    
    for (let j = 1; j <= n; j++) {  //lets loop through all divisors >>> can be optimized using array from UNIT2
      if (i % j !== 0) { //check not passed>>>get out of inner loop
        
        break;
      }
      //if we on final iter. step and all checks passed >>> job done
      if (n === j) {
        return i;
      }

    } 

  }

}

//fCC test passed