function swap(arr, i, j) {
  [arr[i], arr[j]] = [arr[j], arr[i]];
}

function getPartitiionIndex(arr, i, j) {
  const pivot = arr[Math.floor((i + j) / 2)];
  while (i <= j) {
    while (arr[i] < pivot) {
      // left is in correct position
      i++;
    }
    while (arr[j] > pivot) {
      // right is in correct position
      j--;
    }
    if (i <= j) {
      swap(arr, i, j);
      i++;
      j--;
    }
  }
  return i;
}

Untitled

scan array starting after pivot element (swapIdx = 0) and compare every item with pivot element, for every smaller element found: first increase swapIdx and then swap it with element at swapIdx. After loop, finally swap pivot with element at swap index.

function pivot(arr, left, right) {
  let pivot = arr[left];
  let swapIndex = left;

  for (let i = left + 1; i <= right; i++) {
    if (arr[i] < pivot) {
      swap(arr, ++swapIndex, i);
    }
  }

  swap(arr, left, swapIndex);

  return swapIndex;
}

recursively apply to parts before and after pivot element checking if start < end

function quickSort(arr, left, right) {
  if (left < right) {
  
    const pivot = getPartitiionIndex(arr, left, right);
    
    quickSort(arr, left, pivot - 1);
    quickSort(arr, pivot + 1, right);
  }
  return arr;
}