前端面试手写题,看完就会~

177 阅读3分钟

一般面试1个小时,20分钟会让你手写代码,有些题目写不出来,还是非常影响面试官对你评价的。手写题包括:常见的方法编程题leetcode的实现,本文精选常见的一些面试手写题,供大家参考、交流、学习。

1. 判断js常见的类型 ⭐️⭐️⭐️⭐️⭐️

function type(value) {
    return Object.prototype.toString.call(value)
}

2. 实现call ⭐️⭐️⭐️⭐️




Function.prototype.myCall = function (context = window) {
    // 1. 判断调用myCall的类型, 因为call方法是函数原型上的方法
    if (typeof this !== 'function') {
        throw new TypeError('caller is not a function');
    }

    // 2. 将fn赋值给context的一个属性,这样执行context.fn(), 函数内的this指向就是context了
    context.fn = this;
    // 3. 获取除了context以外的函数参数
    const args = [...arguments].slice(1);
    // 4. 执行函数
    const result = context.fn(...args);
    // 5. 删除属性
    delete context.fn;
    return result;
}


// test ...
const obj = {
    name: 'a'
}

function fn(a,b) {
    console.log(this.name, a, b)
}
fn.myCall(obj, 1) // 'a' 1

3. 实现apply⭐️⭐️⭐️⭐️


Function.prototype.myApply = function(context = window) {
    if (typeof this !== 'function') {
        throw new TypeError('caller is not a function');
    }
    context.fn = this;
    // 这里函数第二个参数可能是undefined 或者 数组
    const args = arguments[1] || [];
    const result = context.fn(...args);
    delete context.fn;
    return result;
}

// test ...
const obj = {
    name: 'a'
}

function fn(a,b) {
    console.log(this.name, a, b)
}
fn.myApply(obj, [1, 2])

4. 实现bind ⭐️⭐️⭐️⭐️


Function.prototype.myBind = function(context = window) {
    if (typeof this !== 'function') {
        throw new TypeError('caller is not a function');
    }
    context.fn = this;
    const args = [...arguments].slice(1)
    return function() {
        const result = context.fn(...args);
        delete context.fn;
        return result;
    }
}

// test ...
const obj = {
    name: 'a'
}

function fn(a,b) {
    console.log(this.name, a, b)
}
const o = fn.myBind(obj, 1, 2)
o()

5. 实现sleep:休眠一段时间再执行后续代码 ⭐️⭐️⭐️⭐️

const sleep = time => new Promise(resolve => setTimeout(resolve, time))

// test...
async function main() {
    await sleep(2000)
    console.log('after sleep')
}
main()

6. delay: 推迟多久后执行函数 ⭐️⭐️⭐️⭐️

function delay(fn, time, ...args) {
    return new Promise(resolve => {
        setTimeout(() => {
            Promise.resolve(fn(...args)).then(resolve)
        }, time)
    })
}

// test ...
async function main(a) {
    console.log(a)
}

delay(main, 3000, 123)

7. 实现Promise.all ⭐️⭐️⭐️⭐️⭐️

function myAll(arr) {
    let results = []
    return new Promise((resolve,reject) => {
        let count = 0
        arr.forEach((item, index) => {
            Promise.resolve(item).then(res => {
                results[index] = res
                
                if (++count === arr.length) {
                    resolve(results)
                }        
            }).catch(e => reject(e))
        })
        
    })
}
// test ....
const p1 = () => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('p1')
        }, 2000)
    })
}
const p2 = () => Promise.resolve(2)

const p3 = 3

myAll([p1(), p2(), p3]).then(res => {
    console.log(res)
})

8. 实现isArray ⭐️⭐️⭐️

function isArray(value) {
    return Object.prototype.toString.call(value) === '[object Array]'
}
// test...
console.log(isArray([]))
console.log(isArray({}))
console.log(isArray(1))

9. 实现flatten: 数组扁平化 ⭐️⭐️⭐️⭐️⭐️

const arr = [1, [2], [3], [[4, 5]]]

function flat(arr) {
    return arr.reduce((prev, cur) => {
        return prev.concat(Array.isArray(cur) ? flat(cur) : cur)
    }, [])
}

console.log(flat(arr))

10. 实现forEach, reduce ⭐️⭐️⭐️⭐️⭐️


Array.prototype.myForEach = function(cb) {
    const arr = this;
    for (let i = 0; i < arr.length; i++) {
        cb(arr[i], i)
    }
}
// test ...
const arr = [
    { name: 'xz', age: 18},
    { name: 'tl', age: 20},
    { name: 'xl', age: 20},
]
arr.myForEach((item, index) => {
    console.log(item ,index)
})


Array.prototype.myReduce = function(cb, initValue) {
    const arr = this;
    let result = initValue
    for (let i = 0; i < arr.length; i ++) {
        result = cb(result ,arr[i], i)
    }
    return result
}
// test ,..
const s = arr.myReduce((prev, cur, index) => {
    return prev + cur.age
}, 0)
console.log(s)

11. 实现trim ⭐️⭐️⭐️⭐️


function trim(str) {
    return str.trim?.() || str.replace(/^\s+|\s+$/g)
}

console.log(trim('  fdgbhn '))

12. 实现冒泡排序 ⭐️⭐️⭐️⭐️

function bubbleSort(arr) {
  const len = arr.length;
  for (let i = 0; i < len; i ++) {
    for (let j = i + 1; j < len; j ++) {
      if (arr[i] > arr[j]) {
        const temp = arr[i];
        arr[i] = arr[j]
        arr[j] = temp
      }
    }
  }
  return arr
}

13. 实现快排 ⭐️⭐️⭐️⭐️

function quickSort(arr) {
  const len = arr.length;
  if (len <= 1) return arr
  const midIndex = Math.floor(len / 2)
  let left = []
  let right = []
  const midValue = arr[midIndex]
  for (let i = 0; i < len; i ++) {
    if (i !== midIndex) {
      if (arr[i] < midValue) {
        left.push(arr[i])
      } else {
        right.push(arr[i])
      }
    }
  }
  return arguments.callee(left).concat([midValue], arguments.callee(right))
}


14. 实现instanceof ⭐️⭐️⭐️


function instanceOf(obj, object) {
  let O = object.prototype
  obj = obj.__proto__;
  while(true) {
    if (obj === null) {
      return false;
    }
    if (O === obj) {
      return true
    }
    obj = obj.__proto__;
  }
}

15. 实现new操作符 ⭐️⭐️⭐️

function _new(fn, ...args) {
  const obj = Object.create(fn.prototype)
  const result  = fn.apply(obj, args)
  return result instanceof Object ? result : obj
}

// test. ..
function Animal(name) {
  this.name = name;
}

const dog = _new(Animal, 'dog')
console.log(dog)

16. 柯里化函数curry ⭐️⭐️⭐️⭐️

function curry(fn) {
  const len = fn.length;
  return function currying(...args) {
    if (len === args.length) {
      return fn.apply(null, args)
    } 
    return function (...args2) {
      return currying.apply(null, [...args, ...args2])
    }
  }
}

//  test ...
function add (x, y) {
  return x + y
}
const fn = curry(add)

console.log(fn(2)(3))

17. 部门数据结构转换 ⭐️⭐️⭐️⭐️⭐️


// 给定的数据结构
let arr = [
  { id: 1, name: "部门1", pid: 0 },
  { id: 2, name: "部门2", pid: 1 },
  { id: 3, name: "部门3", pid: 1 },
  { id: 4, name: "部门4", pid: 3 },
  { id: 5, name: "部门5", pid: 4 },
];

// 转化成带部门层级的结构
// [
//   {
//       "id": 1,
//       "name": "部门1",
//       "pid": 0,
//       "children": [
//           {
//               "id": 2,
//               "name": "部门2",
//               "pid": 1,
//               "children": []
//           },
//           {
//               "id": 3,
//               "name": "部门3",
//               "pid": 1,
//               "children": [
//                   // 结果 ,,,
//               ]
//           }
//       ]
//   }
// ]

const transform = (items) => {
  let result = [];
  const itemMap = {};
  for (const item of items) {
    itemMap[item.id] = { ...item, children: [] };
  }

  for (const item of items) {
    const id = item.id;
    const pid = item.pid;
    const treeItem = itemMap[id];
    if (pid === 0) {
      result.push(treeItem);
    } else {
      if (!itemMap[pid]) {
        itemMap[pid] = {
          children: [],
        };
      }
      itemMap[pid].children.push(treeItem);
    }
  }
  return result;
};

console.log(transform(arr));

18. 实现一个发布订阅事件 ⭐️⭐️⭐️⭐️⭐️



class Subscribe {
  eventMap = {}

  on(event, cb) {
    if (this.eventMap[event]) {
      this.eventMap[event].push(cb)
    } else {
      this.eventMap[event] = [cb]
    }
  }

  emit(event, ...args) {
    if (!this.eventMap[event]) console.log("-----no-event")
    if (this.eventMap[event]) {
      this.eventMap[event].forEach(fn => {
        fn(...args)
      })
    }
  }

  off (event) {
    delete this.eventMap[event]
  }
}


// test ...
const s = new Subscribe()
s.on('click', x => console.log(x))
s.emit('click', { id: 3 } )
s.off('click')
s.emit('click', { id: 3 } )

19. 求数组中最大的数 ⭐️⭐️⭐️⭐️⭐️

function max(arr) {
  if (arr.length === 0) return 0
  return arr.reduce((prev, cur) => prev > cur ? prev : cur)
}

console.log(max([1,2,3,4,5,6,7]))

20. 求出现次数最多的字符 ⭐️⭐️⭐️⭐️⭐️

// 解法一:
function maxChar(str) {
  const dict = {}
  for (const s of str) {
    dict[s] = (dict[s] || 0) + 1
  }
  let max = ['', 0]
  Object.keys(dict).forEach(item => {
    if (dict[item] > max[1]) {
      max = [item , dict[item]]
    }
  })
  return max
}
console.log(maxChar(str))

// 优化后:
function maxChar(str) {
  const dict = {}
  let maxChar = ['', 0]
  for (const s of str) {
    dict[s] = (dict[s] || 0) + 1;
    if (dict[s] > maxChar[1]) {
      maxChar = [s, dict[s]]
    }
  }
  return maxChar
}

const str = 'asdfdgfhjhkassaaaaa'

console.log(maxChar(str))

21. 对字符编码压缩 ⭐️⭐️⭐️⭐️⭐️

// Input: 'aaaabbbccd'
// Output: 'a4b3c2d1'

const str = "aaaabbbccd"
const dict = {
  a: 4,
  b: 3,
  c: 2,
  d: 1
}
function encode(str) {
  const dict = {}
  for (const s of str) {
    dict[s] = (dict[s] || 0) + 1
  }
  let result = ''
  Object.keys(dict).forEach(item => {
    result += item + dict[item]
  })
  return result
}
console.log(encode(str)) // a4b3c2d1

22. LRU cache ⭐️⭐️⭐️⭐️⭐️

class LRUCache {
  constructor(limit) {
    this.limit = limit;
    this.cache = new Map();
  }

  get(key) {
    if (!this.cache.has(key)) return undefined;
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }

  put(key, value) {
    if (this.cache.has(key)) this.cache.delete(key);
    else if (this.cache.size >= this.limit) {
      this.cache.delete(this.cache.keys().next().value);
    }
    this.cache.set(key, value);
  }
}

// ["LRUCache","put","put","get","put","get","put","get","get","get"]
// [[2],[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]]
const lruCache = new LRUCache(2);
lruCache.put(1, 1);
lruCache.put(2, 2);
const res1 = lruCache.get(1);
lruCache.put(3, 3);
const res2 = lruCache.get(2);
lruCache.put(4, 4);
const res3 = lruCache.get(1);
const res4 = lruCache.get(3);
const res5 = lruCache.get(4);

console.log(res1, res2, res3, res4, res5);
// 1 undefined undefined 3 4

23. 实现jsonp ⭐️⭐️⭐️⭐️⭐️



function jsonp({ url, params, onData }) {
  const script = document.createElement('script');
  script.src = `${url}/${JSON.stringify({ callback: 'callback', ...params })}`
  window['callback'] = onData;
  document.body.appendChild(script)
}

jsonp({
  url: 'localhost:8000',
  params: {
    id: 1
  },
  onData(data) {
    console.log('data', data)
  }
})

24. 给数字添加千位符 ⭐️⭐️⭐️⭐️⭐️

function numFormat(num) {
  num = num.toString().split("."); // [123456789, 123456678]
  const arr = num[0].split("").reverse();
  let res = [];
  for (let i = 0; i < arr.length; i++) {
    if (i !== 0 && i % 3 === 0) {
      res.push(",");
    }
    res.push(arr[i]);
  }
  res.reverse();
  if (num[1]) {
    res = res.join("") + "." + num[1];
  } else {
    res = res.join("");
  }
  return res;
}

console.log(numFormat(123456789.12345678))

25. 斐波那契数列 ⭐️⭐️⭐️⭐️⭐️


// 1,1,2,3,5,8,13.........n
// -----------100----------

function fib(n) {
  if (n <= 2) return 1
  return fib(n-1) + fib(n-2)
}

26. 斐波那契数列: 重复计算优化 ⭐️⭐️⭐️⭐️⭐️

let fib = (function () {
    let memo = new Map()
    return function(n) {
        const memorized = memo.get(n)
        if (memorized) return memorized
        if (n <= 2) return 1
        let f1 = fib(n - 1)
        let f2 = fib(n - 2)
        memo.set(n-1, f1)
        memo.set(n-2, f2)
        return f1 + f2
    }
})()

console.log(fib(50))

27. 斐波那契数列: 堆栈优化 ⭐️⭐️⭐️⭐️⭐️

function fib(n, current = 0, next = 1) {
    if (n === 0) return 0
    if (n === 1) return next;
    return fib(n - 1, next, current + next)
}

28. 斐波那契数列: 自下而上求解 ⭐️⭐️⭐️⭐️⭐️

// 将数值保存在dp数组里
function fib(n) {
    let dp = []
    dp[0] = 0
    dp[1] = 1
    dp[2] = 1

    for (let i = 3; i <= n; i ++) {
        dp[i] = dp[i-1] + dp[i-2]
    }
    return dp[n]
}

29. 叶子节点路径和 ⭐️⭐️⭐️⭐️

let tree = {
  val: 1,
  left: {
    val: 2,
    left: {
      val: 4,
      left: null,
      right: null,
    },
    right: {
      val: 5,
      left: null,
      right: null,
    },
  },
  right: {
    val: 3,
    left: null,
    right: null,
  },
};

// 递归遍历二叉树,同时记录路径数值,遇到叶子节点计算路径和。

function hasPathSum(root, target) {
  if (!root) return false;
  if (!root.left && !root.right) {
    // 叶子节点与剩余的数比较
    return target === root.val;
  }
  return (
    hasPathSum(root.left, target - root.val) ||
    hasPathSum(root.right, target - root.val)
  );
}

console.log(hasPathSum(tree, 8));

30. deepClone ⭐️⭐️⭐️⭐️⭐️



const obj = {
  a: 1,
  b: {
    c: 1
  }
}

function deepClone(obj) {
  if (typeof obj === null) return null;
  if (typeof obj !== "object") return obj;
  let result = Array.isArray(obj) ? [] : {}
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] =
        typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key];
    }
  }
  return result;
}

const o = deepClone(obj)
o.b.c = 2
console.log(obj)

31. throttle ⭐️⭐️⭐️⭐️⭐️


// n 秒内只执行一次
function throttle(fn, wait) {
  let lastTime = 0
  return function () {
    const now = Date.now()
    if (now - lastTime > wait) {
      fn.apply(null, arguments)
      lastTime = now
    }
  }
}

const test = i => console.log(`test+${i}`)

const throttled = throttle(test, 1000)

for(let i = 0; i < 10; i ++) {
  throttled(i)
}

32. debounce ⭐️⭐️⭐️⭐️⭐️


// n 秒后执行最后一次的请求

function debounce(fn, delay) {
  let timer = null;
  return function () {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(null, arguments)
    }, delay)
  }
}

const test = i => console.log(`test-----${i}`)
const debounced = debounce(test, 1000)

for(let i = 0; i < 10; i++) {
  debounced(i)
}

33. isEqual ⭐️⭐️⭐️⭐️⭐️


var obj1 = {
  x1: 1,
  x2: { x: 1, y: 1 }
};

var obj2 = {
  x1: 1,
  x2: { x: 1, y: 1 }
};



function isObject(obj) {
  return typeof obj === 'object' && obj !== null;
}

function isEqual(obj1, obj2) {
  if (!isObject(obj1) || !isObject(obj2)) {
    return obj1 === obj2
  }
  if (obj1 === obj2) return true;
  const obj1Keys = Object.keys(obj1)
  const obj2Keys = Object.keys(obj2)
  if (obj1Keys.length !== obj2Keys.length) return false;
  for (const key in obj1) {
    const res = isEqual(obj1[key], obj2[key])
    console.log('-----res', obj1[key], obj2[key])
    if (!res) return false;
  }
  return true
}


console.log(isEqual(obj1, obj2))

34. compose ⭐️⭐️⭐️⭐️⭐️

// 从左向右计算
const composeLeft = (...fns) => fns.reduce((f,g) => (...args) => g(f(...args)))

// 从右向左计算
const composeRight = (...fns) => fns.reduceRight((f, g) => (...args) => g(f(...args)))
const add5 = x => x + 5
const multiply = x => x * 10
const left = composeLeft(
  add5,
  multiply
)
const right = composeRight(
  add5,
  multiply
)
console.log(left(10)) // 105
console.log(right(10)) // 105

35. shuffle: 随机洗牌函数 ⭐️⭐️⭐️


const arr = [3, 1, 5, 4]

//随机洗牌函数
const shuffle = (list) => list.sort((x, y) => Math.random() - 0.5)

console.log(shuffle(arr))

36. sample: 从数组中随机取一个数 ⭐️⭐️⭐️

// 从数组中随机取一个数



Array.prototype.sample = function () {
  if (!Array.isArray(this)) return new TypeError('this is not array')
  const len = this.length;
  return this[Math.floor(Math.random() * len)]
}

// Math.random() // (0, 1)
// len (1, 4)
const arr = [1, 2, 3, 4]
const random = arr.sample()

console.log(random)

37. difference: 取数组交集 ⭐️⭐️⭐️⭐️⭐️



// 取数组交集

const arr1 = [1, 2, 3, 5]
const arr2 = [1, 2, 4]

const intersection = (...list) => {
  const result = list.reduce((x, y) => {
    return x.filter(i => y.includes(i))
  })
  return [...new Set(result)]
}
console.log(intersection(arr1, arr2))

ps: github-code

最后祝大家跳槽成功,财源滚滚🧧🧧🧧