你不知道的N条前端面试题(一)

105 阅读3分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

  1. varlet const 的区别?

    • var 是 ES5 语法,let const是 ES6 语法;
    • var 声明变量存在变量提升,letconst 不存在变量提升
    • let const 有块级作用域, var 没有
    • varlet 是变量,可修改;const 是常量,不可修改(但是可以修改对象里面的键值);
    • 同一作用域下 letconst 不能声明同名变量,var 可以
    • const 一旦声明必须赋值,不能使用 null 占位;
  2. typeof() 能判断哪些类型

    • string number boolean undefined symbol object(注意,typeof null === 'object') function
  3. 列举强制类型转换和隐式类型转换

    • 强制:parseInt parseFloat toString
    • 隐式:if、逻辑运算、==、+ 拼接字符串
  4. 手写深度比较,模拟 lodash isEqual

    // 判断是否是对象或数组
    function isObject(obj) {
      return typeof obj === 'object' && obj !== null
    }
    
    // 深度比较
    function isEqual(obj1, obj2) {
      if (!isObject(obj1) || !isObject(obj2)) {
        // 值类型(注意,参与 equal 的一般不会是函数)
        return obj1 === obj2
      }
      if (obj1 === obj2) {
        return true
      }
      // 两个都是对象或数组,而且不相等
      // 1. 先取出 obj1 和 obj2 的 keys,比较个数
      const obj1Keys = Object.keys(obj1)
      const obj2Keys = Object.keys(obj2)
      if (obj1Keys.length !== obj2Keys.length) {
        return false
      }
      // 2. 以 obj1 为基准,和 obj2 一次递归比较
      for (let key in obj1) {
        // 比较当前 key 的 val 一 递归!!!
        const res = isEqual(obj1[key], obj2[key])
        if (!res) {
          return false
        }
      }
      // 3. 全相等
      return true
    }
    
    // 测试1
    const obj1 = {
      a: 100,
      b: {
        x: 100,
        y: 200
      }
    }
    const obj2 = {
      a: 100,
      b: {
        x: 100,
        y: 200
      },
      c: 300
    }
    console.log( isEqual(obj1, obj2) )
    
    // 测试2
    const arr1 = [1, 2, 3]
    const arr2 = [1, 2, 3, 4]
    console.log( isEqual(arr1, arr2) )
    
  5. split() 和 join() 的区别

    • split()join() 函数通常都是对字符或字符串的操作
    • split() 方法使用指定的分隔符字符串将一个 String 对象分割成子字符串数组;
    • join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串;
    '1-2-3'.split('-') // [1, 2, 3]
    [1, 2, 3].join('-') // '1-2-3'
    
  6. 数组的 pop push unshift shift 分别做什么?

    • pop 删除数组的最后一个元素并返回删除的元素
    • push 向数组的末尾添加一个或更多元素,并返回新的长度
    • unshift 向数组的开头添加一个或更多元素,并返回新的长度
    • shift 删除并返回数组的第一个元素
    // 用法
    let fruits = ['Banana', 'Orange', 'Apple', 'Mango']
    
    fruits.pop() // Banana, Orange, Apple
    fruits.push('Kiwi') // Banana, Orange, Apple, Mango, Kiwi
    fruits.unshift('Lemon', 'Pineapple') // Lemon, Pineapple, Banana, Orange, Apple, Mango
    fruits.shift() // Orange, Apple, Mango
    
  7. 数组 slicesplice 的区别

    • slice 选取数组的一部分,并返回一个新数组
    • splice 从数组中添加或删除元素
    // 用法
    let fruits = ['Banana', 'Orange', 'Apple', 'Mango']
    
    fruits.slice(1, 3) // Orange, Apple
    fruits.splice(2, 0, 'Lemon') // Banana, Orange, Lemon, Apple, Mango
    
  8. [10, 20, 30].map(parseInt) 返回结果是什么?

    • map 通过指定函数处理数组的每个元素,并返回处理后的数组
    const res = [10, 20, 30].map(parseInt)
    console.log(res) // [ 10, NaN, NaN ]
    
    // 拆解
    [10, 20, 30].map((num, index) => {
        return parseInt(num, index)
    })
    
    // 相当于 parseInt(10, 0) parseInt(20, 1) parseInt(30, 2) 的返回值
    
  9. 函数 callapply 的区别

    • 两者都是改变函数执行时的上下文,即改变 this 的指向
    • call 使用一个指定的 this 值和单独给出一个或多个参数来调用一个函数
    • apply 使用一个指定的 this 值和单独给出一个或多个参数的数组来调用一个函数
    fn.call(this, p1, p2, p3, ...)
    fn.apply(this, arguments)
    
  10. ajax 请求 get 和 post 的区别

    • get 一般用于查询操作,post 一般用于提交操作
    • get 参数拼接在 url 上,post 参数放在请求体内(数据体积可以更大)
    • 安全性:post 易于防止 CSRF