常见的前端面试题手写代码题编程题

290 阅读6分钟

云哥跟大家说下前端面试笔试题和线上面试的时候有时候会出手写题和编程题,外包公司很多都考编程题,自研公司有些也考,可以抽时间做做,不然可能到时候面试一道都做不出来

一、常见的前端面试题手写代码题

1. 防抖

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    防抖: <input id="input" type="text">
</body>
<script>
    // 监听拿到input输入的值
    input.addEventListener('input', function (e) {
        val(e.target.value)
    })
    // 防抖的核心代码
    function fn(time, fun) {
        let flag // 定义状态
        return function (value) {
            clearTimeout(flag)// 在执行之前 清除 定时器的 flag 不让他执行
            flag = setTimeout(() => {
                fun(value)
            }, time)
        }
    }
    const val = fn(1000, function (val) {
        console.log(val)
    })
</script>
</html>

2. 节流

<body>
    <button id="button">手在快1秒执行一次</button>
</body>
<script>
    /*
        定时器版本的
          fns 回调函数
          time 间隔时间
        function throttle(fns, time) {
        let flag // 定义一个空状态
        return function () { // 内部函数访问外部函数形成闭包
            if (!flag) { // 状态为空执行
                flag = setTimeout(() => {
                    fns.apply(this, arguments) // 改变this指向 吧 event 事件对象传出去
                    flag = null
                }, time)
            }
        }
       }
    */

    function throttle(fun, time) {
        let flag = 0
        return function () {
            let now = +new Date().valueOf()
            // 当前的值 减去上一次的值 >= 传过来的事件 执行
            if (now - flag >= time) {
                fun.apply(this, arguments)
                flag = now
            }
        }
    }



    button.onclick = throttle((e) => {
        console.log(e)
    }, 1000)
</script>

3. 深拷贝

   var arr = {
        a: 2,
        b: [33]
    }

  function cloneDeep(arr = {}) {
        // 终止递归 判断如果传进来的数据不是 object 或者 传进来的是一个 null 直接返回
        if (!arr || typeof arr != 'object' || arr == null) return arr
        // 声明一个对象
        let result
        // 用 instanceof 判断原型链上是否有该类型的原型 是 Array => [] ! Arrays =>{}
        arr instanceof Array ? result = [] : result = {}
        // forin 循环对象的key值
        for (const key in arr) {
            //  对象 key 赋值 result
            result[key] = cloneDeep(arr[key])
        }
        return result
   }


    let arr2 = cloneDeep(arr)
    // let arr2 = [...arr]
    arr2.b[0] = 5
    console.log(arr);//  {a: 2, b: Array(1)}   Array  a: 2  b: [33]
    console.log(arr2);//  {a: 2, b: Array(1)}  Array  a: 2  b: [5]
    // 修改新对象不影响原来的对象   

4. 类型判断

    /*
      实现一个类型判断
        []     返回 array
        {}     返回object
        /^$/   RegExp
        1      number
   */


    //   第一种方案
    function type_of(obj) {
        let res = Object.prototype.toString.call(obj).split(' ')[1] // 输出 RegExp]
        /*
        res.substring(0, res.length - 1) 从第 0 项开始截取 截取到它的长度 -1 
        也就是最后一项的前一项 把最后的一项  ] 给干掉
        */
        return res.substring(0, res.length - 1).toLowerCase()
    }


    // 第二种方案
    function type_of(obj) {
        // .slice(8, -1) 从 第 8项开始截取 -1 不要最后一项
        return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
    }

5. 生产随机数

    // 生成随机数
    function random(min, max) {
        //  Math.floor() 向下进行取证
        return Math.floor(Math.random() * (max - min + 1) + min)
    }
    console.log(random(3, 5))

6. 手写 indexOf

        function myIndexOf(a) {
            // 1、 这个也可以正则实现 下面代码
            // let reg = new RegExp(a)
            // res = reg.exec(this)
            // return res === nu ll ? -1 : res.index
            // 这个也可以正则实现

            let lena = a.length
            y = this.length
            flag = -1
            if (lena > y) return -1
            // 如果输入的字符串大于要检测的字符串直接 -1
            for (let i = 0; i <= y - lena; i++) {
                if (this.substr(i, lena) === a) {
                    // substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符。
                    flag = i
                    break
                }
            }
            return flag
        }
        String.prototype.myIndexOf = myIndexOf
        
    let demo = 'dwanlghMappaw'
    let str = 'h'
    console.log(demo.myIndexOf(str));

7. 数组排序(冒泡)

    function sort(arr) {
        // 外层循环控制的是比较的轮数,你要循环几轮
        //  arr.length (5 ) - 1  = 4
        for (let i = 0; i < arr.length - 1; i++) {
            // 内层循环控制的每一轮交换的次数
            // 第一轮要比较4次   下标为 0     arr.length - 1(4) - i(0)  =  4
            // 第二轮要比较3次   下标为 1     arr.length - 1(4) - i(1)  =  3
            // 第三轮要比较2次   下标为 2     arr.length - 1(4) - i(2)  =  2
            // 第四轮要比较1次   下标为 3     arr.length - 1(4) - i(3)  =  1

            // 内层循环控制的每一轮交换的次数
            for (let j = 0; j < arr.length - 1 - i; j++) {
                // arr[j] 第一项  arr[j + 1] 第二项
                // arr[j] 第二项  arr[j + 1] 第三项
                // ....
                if (arr[j] > arr[j + 1]) {
                    //  大于后一项 做一个交换变量 es6 结构赋值 的变量交换
                    [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
                }
            }
        }
        return arr
    }
    console.log(sort([200, 100, 3, 9, 4]));

8. 数组最大值最小值

    const array = [5, 4, 7, 8, 9, 2];
    let num = array.reduce((a, b) => a > b ? a : b);
    console.log(num) // 9
    let nums = array.reduce((a, b) => a < b ? a : b);
    console.log(nums) // 2

9. 数组去重

        /*
          数组的去重 
        */
        const ylbsz = [1, 35, 6, 78, 66, 6, 35]
        function _set(arr) {
            // 放一个新数组
            const newArr = []
            for (let i = 0; i < arr.length; i++) {
                if (newArr.indexOf(arr[i]) == -1) {
                    newArr.push(arr[i])
                }
            }
            return newArr
        }
        console.log(_set(ylbsz))
        console.log([...new Set([11, 11, 222, 222])])

        // 字符串去重
        let str = '123321你好你好'
        console.log([...new Set(str.split(''))].join(''))

10. instanceOf 手写

    // instanceof
    // 1、只要当前类出现在实例的原型上,结果都为 true 
    // 2、由于我们可以肆意的修改原型的指向,所以检测出来的结果是不准确的
    // 3、不能检测基本数据类型


    const arr = []
    console.log(arr);
    function instance_of(example, classFunc) {    // 实例.__proto__ === 类.prototype   => instanceof
        let classFuncPrototype = classFunc.prototype // 这个就代表类的原型
        proto = Object.getPrototypeOf(example) // example.__proto__    实例的.__proto__
        while (true) {  // 我也不知道你要找多少次  while循环
            if (proto === null) { // 找到最顶层为null就说明没找到 返回 false
                return false
            }
            if (proto === classFuncPrototype) {
                return true
            }
            proto = Object.getPrototypeOf(proto)
        }
    }
    console.log(instance_of(arr, Array));
    console.log(instance_of(arr, Object));
    console.log(instance_of(arr, RegExp));

11. 大小写转换

    /*
    *   @  这里有一个字符串需要将它吧大写转为小写小写转为大写
    *   let str = 'sUnZHIhaO'
    */

    // charCodeAt(N)  返回在指定的位置的字符的 Unicode 编码

    let str = 'sUnZHIhaO'

    function fn(val) {
        return val.replace(/[a-zA-Z]/g, config => {
            // config 每一次正则匹配的结果
            // charCodeAt a ==65 z ==90 判断是否大小写 config.charCodeAt() >= 65 && config.charCodeAt() <= 90
            // 验证字母大小写:把字母转换为大写,看原来的是否是大写,如果是就转换为小写,不是还是原来
            return config.toUpperCase() === config ? config.toLowerCase() : config.toUpperCase()
        })
        console.log(val)
    }
    console.log(fn('sUnZHIhaO'))

12.实现数组扁平化

递归实现

    function flatten(arr){
        let result = []
        for(let i=0,len=arr.length;i<len;i++){
            if(Array.isArray(arr[i])){
                result = result.concat(flatten(arr[i]))
            }else{
                result.push(arr[i])
            }
        }
        return result
    },

ES6扩展运算符

javascript
复制代码
    function flatten(arr){
        while(arr.some(item=>Array.isArray(item))){
            arr = [].concat(...arr)
        }
        return arr
    }

13.解析获取 URL 参数

  • 字符串分割
function getParams() {
  const params = {};
  const search = location.search.substring(1); // 去掉问号
  const pairs = search.split('&'); // 按 & 分割参数

  for (let i = 0; i < pairs.length; i++) {
    const pair = pairs[i].split('=');
    const key = decodeURIComponent(pair[0]); // 解码参数名
    const value = decodeURIComponent(pair[1] || ''); // 解码参数值(如果没有值,则默认为 "")
    params[key] = value; // 存储为对象属性
  }

  return params;
}
  • 使用 URLSearchParams
const getSearchParams = () => {
  const search = new URLSearchParams(window.location.search)
  const paramsObj = {}
  for (const [key, value] of search.entries()) {
    paramsObj[key] = value
  }
  return paramsObj
}

14.实现一个 new 操作符

  • 创建一个新的空对象
  • 使空对象的__proto__指向构造函数的原型(prototype)
  • 把this绑定到空对象
  • 执行构造函数,为空对象添加属性
  • 判断函数的返回值是否为对象,如果是对象,就使用构造函数的返回值,否则返回创建的对象
  • --如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用将返回该对象引用。
function myNew(Con, ...args){
    let obj = {}
    obj.__proto__ = Con.prototype
    let result = Con.call(obj, ...args)
    return result instanceof Object ? result : obj
}
let anini = myNew(Star,'anini',18)
// 相当于
let anini = new Star('anini',18)