• JS面试相关


    深拷贝、浅拷贝、递归、优化
    扁平化
    柯里化
    this指向+原型
    继承
    call、apply、bind
    js取整的方法,parseInt第二个参数是什么
    forEach和map有什么区别,使用场景?
    内存泄漏的场景
    原型链+原型
    严格模式
    Js中for in 和for of的区别
    slice、splice、split 三者的区别
    变量提升、函数提升
    循环引用?如何解决
    null与undefined
    闭包
    数组多种去重方法
    slice是干嘛的,splice是否会改变原数组
    == 和 === 有什么区别?
    什么是事件委托?为什么它是有用的?
    什么是立即执行的函数表达式(IIFE)?
    如何检查一个变量是否是数组?
    描述map、reduce 和 filter 方法。

    这些前端JS面试题涵盖了许多JavaScript的核心和高级概念。我们可以根据不同的主题对它们进行分类。以下是一个分类示例:

    一. 基础概念与语法:

    • null与undefined
    • == 和 === 有什么区别?
    • Js中for in 和for of的区别
    • slice、splice、split 三者的区别
    • 变量提升、函数提升
    • 严格模式

    二. 数据结构与类型操作:

    1.深拷贝、浅拷贝、递归、优化

    浅拷贝:只复制引用,而未复制真正的值,改变其中一个的值,另一个的值也随之改变
    深拷贝:复制真正的值,改变其中一个的值,另一个的值不会改变

    assignAPI实现一级内容深拷贝,二级内容浅拷贝

    assign:一级内容深拷贝,二级及以上浅拷贝 一次把深拷贝和浅拷贝都写出来

    // assin:一级内容深拷贝,二级及以上浅拷贝
    let obj = {name:"Tom", age:18, job:["web"]}
    let objCopy = Object.assign({}, obj)//这里一定要两个参数{},不然就全是深拷贝
    
    // 深拷贝
    console.log(obj)
    console.log(objCopy)
    objCopy.job[0] = "IT"
    console.log(obj)
    console.log(objCopy)
    
    console.log("--------------------")
    
    // 浅拷贝
    console.log(obj)
    console.log(objCopy)
    objCopy.name = "Mick"
    console.log(obj)
    console.log(objCopy)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    let objCopy = Object.assign({}, obj)//这里一定要两个参数{},不然就全是浅拷贝

    递归实现深拷贝

    递归实现深拷贝主要是对对象的每一个属性进行递归复制。下面是一个递归实现深拷贝的基本示例:(核心步骤:使用instanceof检查对象(用typeof就要多加一个判断不等于null的条件)循环引用处理

    循环引用:WeakMap 用于存储已经被复制过的对象。如果在递归的过程中遇到同一个对象,则直接从 WeakMap中获取,以此避免循环引用的问题。

    function deepClone(target, map = new Map()) {
        if (typeof target === 'object' && target !== null) {
            // 避免循环引用问题
            if (map.has(target)) {
                return map.get(target);
            }
    
            // 处理数组和对象的情况
            const cloneTarget = Array.isArray(target) ? [] : {};
            map.set(target, cloneTarget);
    
            for (let key in target) {
                if (target.hasOwnProperty(key)) {
                    cloneTarget[key] = deepClone(target[key], map);
                }
            }
    
            return cloneTarget;
        } else {
            return target;
        }
    }
    
    // 示例
    const obj = {
        num: 0,
        str: '',
        boolean: true,
        unf: undefined,
        nul: null,
        obj: { name: 'I am an object', id: 1 },
        arr: [0, 1, 2],
        func: function() { console.log('I am a function') },
        date: new Date(0),
        reg: new RegExp('/I am a regular expression/ig'),
        [Symbol('key')]: 'I am a symbol',
        error: new Error('I am an error object'),
        map: new Map([['name', 'I am a map']]),
        set: new Set([1, 'I am a set'])
    };
    
    const clonedObj = deepClone(obj);
    
    console.log(clonedObj);
    console.log(clonedObj.obj !== obj.obj);  // true,说明确实进行了深拷贝
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    注意:这个示例并不完整,例如对于某些特殊对象(如 FunctionDateRegExpErrorMapSet 等),可能还需要进行特定的处理。此外,不同的应用场景可能对深拷贝的需求有所不同,因此需要根据具体情况对上述代码进行适当的调整或扩展。

    2.typeof 和 instanceof的区别

    在JavaScript中,typeofinstanceof 用于确定变量的类型,但它们在应用和行为上有所不同。

    1. typeof

      • 对于原始类型(如'string', 'number', 'boolean'等),typeof运行得很好。
      • 但对于数组和普通对象,typeof都返回'object',这会引起一些混淆。
      • 对于nulltypeof也返回'object',这是一个著名的JavaScript错误。
    2. instanceof

      • 它基于原型链来工作,检查左侧的对象是否是右侧构造函数的实例。
      • 对于自定义对象或者其他内置对象如Array、Date等,使用instanceof更为准确。

    3.数组多种去重方法

    数组去重的5种方法:
    1、用“[…new Set(arr)]”语句去重;
    2、用“Array.from(new Set(arr))”语句去重;
    3、利用indexOf()去重;
    4、利用includes()去重;
    5、利用filter()去重。

    数组去重的方法

    1、[…new Set(arr)]

    const arr = [1, 2, 3, 2, 3];
    
    [...new Set(arr)]; // [1, 2, 3]
    
    • 1
    • 2
    • 3

    2、Array.from(new Set(arr))
    加粗样式

    const arr = [1, 2, 3, 2, 3];
    
    Array.from(new Set(arr)); // [1, 2, 3]
    
    • 1
    • 2
    • 3

    由于 Set 中的元素是唯一的,无论是原始值或者是对象引用,所以可以通过将数组转换成 Set 对象来实现去重

    Array.from方法可以将 Set 对象转换成数组

    3、利用indexOf去重

    function unique(arr) {
        var array = [];
        for (var i = 0; i < arr.length; i++) {
            if (array .indexOf(arr[i]) === -1) {
                array .push(arr[i])
            }
        }
        return array;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。

    4、利用includes

    function unique(arr) {
        var array =[];
        for(var i = 0; i < arr.length; i++) {
                if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
                        array.push(arr[i]);
                  }
        }
        return array
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5、利用filter

    function unique(arr) {
      return arr.filter(function(item, index, arr) {
        //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
        return arr.indexOf(item, 0) === index;
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    描述map、reduce 和 filter 方法。

    如何检查一个变量是否是数组?

    slice是干嘛的,splice是否会改变原数组

    forEach和map有什么区别,使用场景?

    区别
    forEachmap 都是数组的常用方法,但它们有不同的目的和用法。下面是它们之间的主要区别以及各自的使用场景:

    1. 目的:

      • forEach: 主要用于迭代数组并执行某些操作,但不返回一个新数组
      • map: 迭代数组,并对每个元素执行某些操作,然后返回一个新数组,该数组包含与原始数组相同数量的元素(可能已被修改)。
    2. 返回值:

      • forEach: 无返回值(返回undefined)。
      • map: 返回一个新数组。
    3. 是否改变原始数组:

      • forEach: 不直接改变原始数组,但可以在回调中更改原始数组(第二个参数index索引可以用来修改)。
      • map: 不改变原始数组,但新数组的元素可能已被修改。
    4. 使用场景:

      • forEach: 当你只是想对数组的每个元素执行操作,而不关心结果时,如打印每个元素。
      • map: 当你想基于现有数组创建一个新数组时,如将每个数字元素乘以2
    5. 示例:

      const arr = [1, 2, 3, 4, 5];
      
      // 使用 forEach 打印每个元素
      arr.forEach(item => {
          console.log(item);
      });
      
      // 使用 map 创建一个新数组,其中每个数字都乘以2
      const doubled = arr.map(item => item * 2);
      console.log(doubled); // [2, 4, 6, 8, 10]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    什么意思?forEach: 不直接改变原始数组,但可以在回调中更改原始数组。

    当你使用 forEach 遍历数组时,它不会自动更改数组的内容。但是,在 forEach 的回调函数中,你可以手动修改原始数组。

    让我们通过代码来解释:

    1. forEach 不会自动更改数组:

      const arr = [1, 2, 3];
      arr.forEach(item => item * 2);
      
      console.log(arr);  // 输出:[1, 2, 3]
      
      • 1
      • 2
      • 3
      • 4

      尽管我们尝试将每个项乘以2,但原始数组 arr 并没有更改。

    2. forEach 的回调中手动修改原始数组:

      const arr = [1, 2, 3];
      arr.forEach((item, index) => {
          arr[index] = item * 2;
      });
      
      console.log(arr);  // 输出:[2, 4, 6]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      在这个例子中,我们明确地使用了数组的索引来修改原始数组 arr。因此,数组的内容已经更改。

    这就是所说的"forEach 不直接改变原始数组,但可以在回调中通过索引更改原始数组"的意思。

    3. 函数与作用域:

    • 闭包
    • 柯里化
    • call、apply、bind
    • this指向+原型
    • 什么是立即执行的函数表达式(IIFE)?
    1. 对象与原型:

      • 原型链+原型
      • 继承
      • js取整的方法,parseInt第二个参数是什么
    2. 优化与问题解决:

      • 递归、优化
      • 扁平化
      • 内存泄漏的场景
      • 循环引用?如何解决
    3. 事件与异步编程:

      • 什么是事件委托?为什么它是有用的?

    此分类只是为了将相关的概念归入相同的组中,但实际上,不同的面试官可能会采用不同的分类方式,或根据他们想测试面试者的哪一方面的知识来调整问题。

  • 相关阅读:
    探索Java设计模式:中介者模式
    IntelliJ IDEA 简介
    【TensorFlow1.X】系列学习笔记【基础一】
    Chainlink 预言机的原理解析
    纳什均衡求解器
    硬件知识1
    第104天: 权限提升-Linux 系统&环境变量&定时任务&权限配置不当&MDUT 自动化
    QTabWidget 类 (选项卡部件)
    el-form自定义规则后表单验证validate不生效的问题
    RPC 核心原理理论分析
  • 原文地址:https://blog.csdn.net/weixin_43850639/article/details/133044797