# 手撕Javascript ⭐️

# 大数相加

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-18 11:52:17
 * @LastEditors: 41
 * @LastEditTime: 2022-04-18 09:28:36
 * @Description: 
 */

/************************测试区域 ***************************/
let num1 = ['1002', '45646', '456465465']
let num2 = ['46', '456456', '798416132132']
let cnt = 0
for (let i = 0; i < num1.length; i++) {
  if (myadd(num1[i], num2[i]) == test(num1[i], num2[i])) {
    console.log(`示例${i}:TRUE`);
    cnt++
  } else {
    console.log(`示例${i}:FALSE`);
  }
}
console.log(`正确率${(cnt / num1.length) * 100}%`);
console.log(2 ** 53);
console.log(2 ** 53 + 10 - 2 ** 53);
/************************解答区域 ***************************/
/**
 * @description: 大数加法BigInt
 * @param1 {*}
 * @return {*}
 * @detail: 
 * @param {*} num1
 * @param {*} num2
 */
function test (num1, num2) {
  num1 = BigInt(num1)
  num2 = BigInt(num2)
  return (num1 + num2).toString()
}
/**
 * @description: 手写大数加法
 * @param1 {*}
 * @return {*}
 * @detail: 
 * @param {*} num1 
 * @param {*} num2
 */
function myadd (num1, num2) {
  /*************判断输入 */
  if (Object.prototype.toString.call(num1).slice(8, -1) != 'String') {
    throw Error('num1 must be a string!')
  }
  if (Object.prototype.toString.call(num2).slice(8, -1) != 'String') {
    throw Error('num2 must be a string!')
  }
  /**************输入处理 */
  let len1 = num1.length, len2 = num2.length
  if (len1 > len2) {
    num2 = num2.padStart(len1, '0')
  } else {
    num1 = num1.padStart(len2, '0')
  }
  let arr1 = num1.split('').map((item) => {
    return item = +item
  })
  let arr2 = num2.split('').map((item) => {
    return item = +item
  })
  /***************运算处理 */
  let res = [], jinwei = 0
  for (let i = arr1.length - 1; i >= 0; i--) {
    let temp = arr1[i] + arr2[i] + jinwei
    if ((temp / 10) >> 0) {
      jinwei = 1
    } else {
      jinwei = 0
    }
    res.unshift(temp % 10)
  }
  return res.join('');
}


# LRU

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-10 21:24:48
 * @LastEditors: 41
 * @LastEditTime: 2022-03-10 21:24:49
 * @Description: 
 */
/**
 * @param {number} capacity
 */
var LRUCache = function (capacity) {
  const cache = new Map()
  const max = capacity
};

/** 
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function (key) {
  let map = this.cache
  if (map.has(key)) {
    let value = map.get(key)
    map.delete(key)
    map.set(key, value)
    return value
  } else {
    return -1
  }
};

/** 
* @param {number} key 
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function (key, value) {
  const map = this.cache
  if (map.has(key)) {
    map.delete(key)
  }
  map.set(key, value)
  if (map.size > this.max) {
    map.delete(map.keys().next().value)
  }
};

# 比较版本号

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-04 17:36:23
 * @LastEditors: 41
 * @LastEditTime: 2022-03-20 18:41:27
 * @Description:
 */
/*
实现一个方法,用于比较两个版本号(version1、version2)
如果version1 > version2,返回1;
如果version1 < version2,返回-1,其他情况返回0。
版本号规则`x.y.z`,xyz均为大于等于0的整数,至少有x位

输入:compareVersion('0.1', '1.1.1')
输出:-1

输入:compareVersion('13.37', '1.2 ')
输出:1

输入:compareVersion('1.1', '1.1.0')
输出:0
*/
function compareVersion (version1, version2) {
  let ver1 = version1.split('.');
  let ver2 = version2.split('.');
  let max = ver1.length > ver2.length ? ver1.length : ver2.length
  while (ver1.length < max) {
    ver1.push('0')
  }
  while (ver2.length < max) {
    ver2.push('0')
  }
  // console.log(ver1, ver2);
  for (let i = 0; i < ver1.length; i++) {
    if (ver1[i] > ver2[i]) {
      return 1
    } else if (ver1[i] == ver2[i]) {
      continue
    } else {
      return -1
    }
  }
  return 0
}
let a = [
  { v1: "0.1", v2: "1.1.1" },
  { v1: "13.37", v2: "1.2" },
]
for (let i = 0; i < a.length; i++) {
  console.log(compareVersion(a[i].v1, a[i].v2));
}

# 数字中1的个数

点击查看代码
/*
 * @Author: 自迩
 * @Date: 2022-03-06 22:36:00
 * @LastEditTime: 2022-03-07 21:03:13
 * @LastEditors: 41
 * @Description:
 * @FilePath: \面试之路\front-end-interview\javascript\bitCount.js
 */

/*************** 测试区域 *******************/
let num = 0B1100
let cnt = 0
weiyi(num, cnt)       // 位移
indexdeal(num, cnt)   // indexOf
splicedeal(num, cnt)  // indexOf+splice
foreachdeal(num, cnt) // forEach
filterdeal(num)       // filter
reducedeal(num)       // reduce
/*************** 题解区域 *******************/
/**
 * @description: bit移位解法
 */
function weiyi (num, cnt) {
  while (num) {
    if (num % 2 === 1) cnt++
    num >>= 1
  }
  console.log(cnt);
}
/**
 * @description: indexOf解法
 */
function indexdeal (num, cnt) {
  let arr = num.toString(2).split('')
  let index = 0
  while (arr.indexOf('1', index) != -1) {
    cnt++
    index = arr.indexOf('1', index) + 1
  }
  console.log(cnt);
}
/**
 * @description: indexOf+splice解法
 */
function splicedeal (num, cnt) {
  let arr = num.toString(2).split('')
  while (arr.indexOf('1') != -1) {
    arr.splice(arr.indexOf('1'), 1)
    cnt++
  }
  console.log(cnt);
}
/**
 * @description: forEach解法
 */
function foreachdeal (num, cnt) {
  let arr = num.toString(2).split('')
  arr.forEach(item => {
    if (item === '1') cnt++
  })
  console.log(cnt);
}
/**
 * @description: filter解法
 */
function filterdeal (num) {
  let arr = num.toString(2).split('')
  let newarr = arr.filter(item => {
    return item === '1'
  })
  console.log(newarr.length);
}
/**
 * @description: reduce解法
 */
function reducedeal (num) {
  let arr = num.toString(2).split('')
  let res = arr.reduce((pre, cur) => {
    return pre + (+cur)
  }, 0)
  console.log(res);
}

# 不用循环输出0到n-1的数

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-04 17:59:10
 * @LastEditors: 41
 * @LastEditTime: 2022-03-17 20:58:37
 * @Description: 
 */

/***************测试区域 *******************/
// dfs(10)
// deal(10)
// deal2(10)
// deal3(10)
let a = Array.from(new Array(10).keys())
console.log(a);
let b = Array.from({ length: 10 }, (node, i) => i)
console.log(b);
/***************题解区域 *******************/
/**
 * @description: 递归解法
 */
function dfs (x) {
  let arr = []
  function deal (x) {
    if (x < 0) return
    arr.unshift(x)
    // console.log(x);
    deal(x - 1)
  }
  deal(x - 1)
  console.log(arr);
}
/**
 * @description: padEnd解法
 */
function deal (x) {
  let str = ''.padEnd(x, '0')
  let arr = str.split('')
  let cnt = 0
  let res = arr.map(item => {
    cnt += 1
    return +item + cnt - 1
  })
  console.log(res);
}
/**
 * @description: Array.from解法
 */
function deal2 (x) {
  let arr = (new Array(x + 1)).join('0').split('')
  let cnt = -1
  let newarr = arr.map(item => {
    cnt++
    return +item + cnt
  })
  console.log(newarr);

}
/**
 * @description: Array.fill解法
 */
function deal3 (x) {
  let arr = (new Array(x)).fill('0')
  let cnt = -1
  let newarr = arr.map(item => {
    cnt++
    return +item + cnt
  })
  console.log(newarr);
}

# 单词统计

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-13 15:19:19
 * @LastEditors: 41
 * @LastEditTime: 2022-03-13 15:32:31
 * @Description: 
 */
function count (article) {
  article = article.trim().toUpperCase()
  let array = article.match(/[A-z]+/g)
  article = " " + array.join(' ') + " "
  let max = 0, maxword
  for (let i = 0; i < array.length; i++) {
    let word = new RegExp(" " + array[i] + " ", 'g')
    let num = article.match(word).length
    if (num > max) {
      max = num
      maxword = array[i]
    }
  }
  console.log(maxword + ' ' + max);
}
count('Age has reached the end of the beginning of a word')

# Fib数列

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-04-24 17:19:11
 * @LastEditors: 41
 * @LastEditTime: 2022-04-26 17:43:16
 * @Description: 
 */
let fib = function () {
  let memo = [0, 1]
  let dfs = function (n) {
    if (memo[n] == undefined) {
      memo[n] = dfs(n - 2) + dfs(n - 1)
    }
    return memo[n]
  }
  return dfs
}()

let res = fib(10)
console.log(res);

# 全排列

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-13 14:19:02
 * @LastEditors: 41
 * @LastEditTime: 2022-03-24 16:03:09
 * @Description: 
 */
let permute = function (nums) {
  let len = nums.length, visited = new Array(len).fill(false), res = []
  const dfs = (nums, len, depth, path, visited) => {
    if (len == depth) {
      res.push([...path])
    }
    for (let i = 0; i < nums.length; i++) {
      if (!visited[i]) {
        path.push(nums[i])
        visited[i] = true
        dfs(nums, len, depth + 1, path, visited)
        visited[i] = false
        path.pop()
      }
    }
  }
  dfs(nums, len, 0, [], visited)
  return res
}
let nums = [1, 2, 3]
console.log(permute(nums));

# 生成树

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-04-01 15:20:38
 * @LastEditors: 41
 * @LastEditTime: 2022-04-02 18:12:11
 * @Description: 
 */
let strarr = {
  'a-b-c-d': 1,
  'a-b-c-e': 2,
  'a-b-f': 3,
  'a-j': 4,
};
path(strarr)
function path (strarr) {
  let obj = {};
  Object.keys(strarr).forEach((item) => {
    let reg = item.split('-')
    let p = obj;
    for (let i = 0; i < reg.length - 1; i++) {
      let v = reg[i];
      p[v] ?? (p[v] = {});
      p = p[v];
    }
    p[reg.at(-1)] = strarr[item];
  });
}
// let obj = {
//   a: {
//     b: {
//       c: {
//         d: 1,
//         e: 2,
//       },
//       f: 3,
//     },
//     j: 4,
//   },
// };

# 快速排序

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-10 21:25:19
 * @LastEditors: 41
 * @LastEditTime: 2022-05-06 17:59:06
 * @Description: 
 */
/************************测试区域 */
let arr2 = [1231, 45546, 788, 12313, 1, 5, 4]
console.log(mysort2(arr2));
/************************题解区域 */
function mysort2 (arr) {
  if (arr.length < 2) return arr
  let target = arr.splice((arr.length / 2) >> 0, 1), left = [], right = []
  arr.forEach(item => {
    (item < target ? left : right).push(item)
  });
  return mysort2(left).concat(target, mysort2(right))
}
/***********************测试区域 */
let arr = [1231, 45546, 788, 12313, 1, 5, 4]
console.log(mysort(arr));
/************************题解区域 */
function mysort (arr) {
  return quick(arr, 0, arr.length - 1)
}
function quick (arr, left, right) {
  let index
  if (arr.length > 1) {
    index = partition(arr, left, right)
    if (left < index - 1) {
      quick(arr, left, index - 1)
    }
    if (index < right) {
      quick(arr, index, right)
    }
  }
  return arr
}

function partition (arr, left, right) {
  const target = arr[left]
  let i = left, j = right
  while (i <= j) {
    while (arr[i] < target) {
      i++
    }
    while (arr[j] > target) {
      j--
    }
    if (i <= j) {
      [arr[i], arr[j]] = [arr[j], arr[i]]
      i++
      j--
    }
  }
  return i
}

# 千分位分割

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-18 11:37:10
 * @LastEditors: 41
 * @LastEditTime: 2022-04-27 19:13:10
 * @Description: 实现数字的千分位逗号分割
 */


function deal (num) {
  let inputArray = num.toString().split('.')
  let zhengshu = inputArray[0].split('')
  let xiaoshu = (inputArray.length > 1 ? inputArray[1] : '').split('')
  let res1 = [], res2 = []
  while (zhengshu.length) {
    let temp = zhengshu.splice(-3).join('')
    res1.unshift(temp)
  }
  while (xiaoshu.length) {
    let temp = xiaoshu.splice(0, 3).join('')
    res2.unshift(temp)
  }
  if (res2.length)
    return res1.join(',') + '.' + res2.join(',')
  else
    return res1.join(',')
}
/***********测试区域************* */
let num = [123154.465165, 132154, 213456, 12.123456, 123145.1231]
for (let i = 0; i < num.length; i++) {
  console.log(deal(num[i]))
}

# 隔一秒输出数字

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-18 11:20:31
 * @LastEditors: 41
 * @LastEditTime: 2022-03-18 11:27:15
 * @Description: 
 */
const oneToThree = () => {
  const arr = [1, 2, 3];
  arr.reduce((prev, next) => {
    return prev.then(() => {
      return new Promise((resolve) => {
        setTimeout(() => {
          console.log(next);
          resolve();
        }, 1000);
      })
    });
  }, Promise.resolve())
};

// oneToThree();

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i + 1);
  }, (i + 1) * 1000)
}

# 柯里化

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-13 15:39:04
 * @LastEditors: 41
 * @LastEditTime: 2022-04-18 20:15:54
 * @Description: 
 */
/**
 * 将函数柯里化
 * @param fn    待柯里化的原函数
 * @param len   所需的参数个数,默认为原函数的形参个数
 */
function curry (fn, len = fn.length) {
  return _curry.call(this, fn, len)
}

/**
* 中转函数
* @param fn    待柯里化的原函数
* @param len   所需的参数个数
* @param args  已接收的参数列表
*/
function _curry (fn, len, ...args) {
  return function (...params) {
    let _args = [...args, ...params];
    if (_args.length >= len) {
      return fn.apply(this, _args);
    } else {
      return _curry.call(this, fn, len, ..._args)
    }
  }
}

function fn (a, b, c, d) {
  console.log(a, b, c, d);
}
// let _fn = curry(fn)
// _fn(1, 2, 3, 4)
// _fn(1)(2, 3)(4)

/************************************* */
function add () {
  let args = [...arguments]
  let inner = function () {
    args.push(...arguments)
    return inner
  }
  inner.toString = function () {
    return args.reduce((pre, cur) => {
      return pre * cur
    })
  }
  return inner
}
const res = add(1)(2)(3)(4)(5).toString()
console.log(res);

# ObjFlat拍平

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-31 14:24:11
 * @LastEditors: 41
 * @LastEditTime: 2022-04-22 14:56:44
 * @Description: 
 */
/***********************测试区域 */
let obj = {
  name: {
    value: 41,
    a: 1,
    b: 2
  },
  age: {
    value: 20
  },
  other: {
    hobby: {
      music1: 'guita',
      music2: 'sing'
    }
  }
}
let res = myFlat(obj)
console.log(res);
/***********************题解区域 */
function myFlat (obj) {
  let newobj = {}
  function dfs (obj, path) {
    if (Object.prototype.toString.call(obj).slice(8, -1) !== 'Object') {
      newobj[path] = obj
    } else {
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          if (path) dfs(obj[key], path + '-' + key)
          else dfs(obj[key], key)
        }
      }
    }
  }
  dfs(obj, '')
  return newobj
}

# lodashGet

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-04-24 17:09:02
 * @LastEditors: 41
 * @LastEditTime: 2022-04-24 17:17:50
 * @Description: 
 */
function get (object, path, defaultVal = 'undefined') {
  let newPath = []
  if (Array.isArray(path)) {
    newPath = path
  } else {
    // console.log(path);
    newPath = path.replace(/\[/g, '.').replace(/\]/g, '').split('.')
    // console.log(newPath);
  }
  return newPath.reduce((o, k) => {
    // console.log(o, k);
    return (o || {})[k]
  }, object) || defaultVal
}
var object = { 'a': [{ 'b': { 'c': 3 } }] };

console.log(get(object, 'a[0].b.c'));

# DeepClone

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-16 11:24:48
 * @LastEditors: 41
 * @LastEditTime: 2022-03-24 11:19:47
 * @Description: 
 */
function getType (obj) {
  return Object.prototype.toString.call(obj).slice(8, -1)
}
function deepClone (obj, map = new WeakMap()) {
  if (obj === null) return obj
  if (getType(obj) === 'RegExp') return new RegExp(obj)
  if (getType(obj) === 'Date') return new Date(obj)
  if (getType(obj) !== 'Object' && getType(obj) !== 'Array') return obj
  if (map.has(obj)) return map.get(obj)
  let cloneobj = getType(obj) === 'Array' ? [] : {}
  map.set(obj, cloneobj)
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneobj[key] = deepClone(obj[key], map)
    }
  }
  return cloneobj
}
let obj = {
  name: 41,
  arr: [1, { test: 123 }, 3, 4, 5],
  haha: {
    name: 123
  }
}
let newobj = deepClone(obj)
obj.name = 42
obj.arr[0] = 5
obj.arr[1].test = 5
obj.haha.name = 5
console.log(obj, newobj);

# 手写reduce

点击查看代码
/*
 * @Author: 自迩
 * @Date: 2022-03-06 22:22:51
 * @LastEditTime: 2022-03-24 16:45:33
 * @LastEditors: 41
 * @Description:
 * @FilePath: \面试之路\front-end-interview\javascript\myreduce.js
 */
/*************题解区域 *********************/
Array.prototype.myReduce = function (fn, init) {
  if (Object.prototype.toString.call(fn).slice(8, -1) !== 'Function') {
    throw error('first parameter must be Function')
  }
  let arr = this
  let pre = init
  let index = 0
  if (!init) {
    pre = arr[index]
    index++
  }
  for (let i = index; i < arr.length; i++) {
    pre = fn(pre, arr[i], i, arr)
  }
  return pre
}
/*************测试区域 *********************/
let arr = [1, 2, 3]
let result = arr.myReduce((pre, cur) => {
  return pre + cur
}, 0)
console.log(result);


# 手写repeat

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-07 21:41:51
 * @LastEditors: 41
 * @LastEditTime: 2022-03-07 21:51:27
 * @Description: 
 */

console.log(repeat('123', 2));
console.log(repeat2('123', 2));
console.log(repeat3('123', 2));


/**
 * @description: 1.空数组join
 */
function repeat (target, n) {
  return (new Array(n + 1)).join(target)
}
/**
 * @description: 2.省去创建数组
 */
function repeat2 (target, n) {
  return Array.prototype.join.call({
    length: n + 1
  }, target)
}
/**
 * @description: 
 */
function repeat3 (target, n) {
  let res = ''
  while (n--) {
    res += target
  }
  return res
}

# 手写Promise

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-04-06 11:31:29
 * @LastEditors: 41
 * @LastEditTime: 2022-04-06 17:40:19
 * @Description: 
 */
class Commitment {
  static PENDING = '待定'
  static FULFILED = '成功'
  static REJECTED = '拒绝'
  constructor(func) {
    this.status = Commitment.PENDING
    this.result = null
    this.resolveCallbacks = []
    this.rejectCallbacks = []
    // func(this.resolve.bind(this), this.reject.bind(this))
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve (result) {
    setTimeout(() => {
      if (this.status === Commitment.PENDING) {
        this.status = Commitment.FULFILED
        this.result = result
        this.resolveCallbacks.forEach(callback => {
          callback(result)
        })
      }
    })
  }
  reject (result) {
    setTimeout(() => {
      if (this.status === Commitment.PENDING) {
        this.status = Commitment.REJECTED
        this.result = result
        this.rejectCallbacks.forEach(callback => {
          callback(result)
        })
      }
    });
  }
  then (onFULFILED, onREJECTED) {
    return new Commitment((resolve, reject) => {
      onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
      onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
      if (this.status === Commitment.PENDING) {
        this.resolveCallbacks.push(onFULFILED)
        this.rejectCallbacks.push(onREJECTED)
      }
      if (this.status === Commitment.FULFILED) {
        setTimeout(() => {
          onFULFILED(this.result)
        })
      }
      if (this.status === Commitment.REJECTED) {
        setTimeout(() => {
          onREJECTED(this.result)
        })
      }
    })
  }
}


let commitment = new Commitment((res, rej) => {
  res('这次一定')
})
commitment.then(
  result => { console.log(result); },
  result => { console.log(result.message); }
).then(
  result => { console.log(result); },
  result => { console.log(result.message); }
)

# 手写Promise.all

点击查看代码
/*
 * @Author: 41
 * @Date: 2022-03-18 11:28:35
 * @LastEditors: 41
 * @LastEditTime: 2022-05-06 17:56:32
 * @Description: 
 */
Promise.myAll = function (promiseArr) {
  return new Promise((resolve, reject) => {
    const ans = []
    let index = 0
    for (let i = 0; i < promiseArr.length; i++) {
      promiseArr[i]
        .then(res => {
          ans[i] = res
          index++
          if (index === promiseArr.length) {
            this.resolve(ans)
          }
        })
        .catch(err => reject(err))
    }
  })
}
lastUpdate: 5/13/2022, 6:22:38 PM