# @(MarkDown) ###手写JS问题

#####函数节流 throttle throttle 策略的电梯。保证如果电梯第一个人进来后,50毫秒后准时运送一次,不等待。如果没有人,则待机。

let throttle = (fn, delay = 50) => { // 节流 控制执行间隔时间 防止频繁触发 scroll resize mousemove
 let stattime = 0;
 return function (...args) {
     let curTime = new Date();
     if (curTime - stattime >= delay) {
         fn.apply(this, args);
         stattime = curTime;
         }
     }
 }

#####防抖动 debounce debounce 策略的电梯。如果电梯里有人进来,等待50毫秒。如果又人进来,50毫秒等待重新计时,直到50毫秒超时,开始运送。

 let debounce = (fn, time = 50) => { // 防抖动 控制空闲时间 用户输入频繁
  let timer;
  return function (...args) {
      let that = this;
      clearTimeout(timer);
      timer = setTimeout(fn.bind(that, ...args), time);
      }
  }

#####Function的bind实现

Function.prototype._bind = function (context) {
	let func = this
	let params = [].slice.call(arguments, 1)
	return function () {
		params = params.concat([].slice.call(arguments, 0))
		func.apply(context, params)
	}
}

#####函数组合串联compose(koa reduce中间件)
// 组合串联
let fn1 = (a) => a + 1;
let fn2 = (b) => b + 2;
let fn3 = (c) => c + 3;

let funs = [fn1, fn2, fn3];

let compose = (func) => {
    return arg => func.reduceRight((composed, fn) => fn(composed), arg);
}
console.log(compose(funs)(100)); // 相当于fn1(fn2(fn3(100)))

#####数组展平

let arr = [[1, 2], 3, [[[4], 5]]]; // 数组展平
function flatten(arr) {
    return [].concat(
        ...arr.map(x => Array.isArray(x) ? flatten(x) : x)
    )
}

#####插入排序

插入排序 从后往前比较 直到碰到比当前项 还要小的前一项时 将这一项插入到前一项的后面

function insertSort(arr) {
  let len = arr.length;
  let preIndex, current;
  for (let i = 1; i < len; i++) {
    preIndex = i - 1;
    current = arr[i]; // 当前项
    while (preIndex >= 0 && arr[preIndex] > current) {
      arr[preIndex + 1] = arr[preIndex]; // 如果前一项大于当前项 则把前一项往后挪一位
      preIndex-- // 用当前项继续和前面值进行比较
    }
    arr[preIndex + 1] = current; // 如果前一项小于当前项则 循环结束 则将当前项放到 前一项的后面
  }
  return arr;
}

#####选择排序 > 选择排序 每次拿当前项与后面其他项进行比较 得到最小值的索引位置 然后把最小值和当前项交换位置
function selectSort(arr) {
  let len = arr.length;
  let temp = null;
  let minIndex = null;
  for (let i = 0; i < len - 1; i++) { // 把当前值的索引作为最小值的索引一次去比较
    minIndex = i; // 假设当前项索引 为最小值索引
    for (let j = i + 1; j < len; j++) { // 当前项后面向一次比小
      if (arr[j] < arr[minIndex]) { // 比假设的值还要小 则保留最小值索引
        minIndex = j; // 找到最小值的索引位置
      }
    }
    // 将当前值和比较出的最小值交换位置
    if (i !== minIndex) {
       temp = arr[i]
       arr[i] = arr[minIndex];
       arr[minIndex] = temp;
    }
  }
  return arr;
}

#####冒泡排序

冒泡排序 相邻两项进行比较 如果当前值大于后一项 则交换位置


#####快速排序(递归)

function quickSort(arr) {
if (arr.length <= 1) return arr;
let midIndex = Math.floor(arr.length / 2);
let midNum = arr.splice(midIndex, 1)[0];
let left = [];
let right = [];
for(let i = 0; i < arr.length; i++) {
    let cur = arr[i];
    if (cur <= midNum) {
        left.push(cur);
    } else {
        right.push(cur);
    }
}
return quickSort(left).concat(midNum, quickSort(right));
}

let arr = [2, 4, 12, 9, 22, 10, 18, 6];
quickSort(arr);

#####数组去重的几种方法

// 1  es6
let newArr = [...new Set(arr)];
// 2  
Array.prototype.unique2 = function() {
let newArr = [];
let len = this.length;
for(let i = 0; i < len; i++) {
    let cur = this[i];
    if(newArr.indexOf(cur) === -1) {
        newArr[newArr.length] = cur;
    }
}
return newArr;
}
console.log(arr.unique1());
// 3 最快
Array.prototype.unique4 = function() {
let json = {}, newArr = [], len = this.length;
for(var i = 0; i < len; i++) {
    let cur = this[i];
    if (typeof json[cur] == "undefined") {
        json[cur] = true;
        newArr.push(cur)
    }
}
return newArr;
}
console.log(arr.unique4());

#####千叶符

 let str1 = '2123456789';
let str2 = '2123456789.12';

// 利用正向预查 匹配 开头一个数字\d 后面匹配这个数字后面必须是三个数字为一组为结尾或小数为结尾
function thousandth(str) { 
    let reg = /\d(?=(?:\d{3})+(?:\.\d+|$))/g; 
    return str.replace(reg, (...rest) => rest[0] + ',');
}
console.log(thousandth(str1)); // 2,123,456,789
console.log(thousandth(str2)); // 2,123,456,789.12

答案:

	str.replace(/(\d)(?=(?:\d{3})+$)/g, ' $1,')