带你速通春招面试,前端js面试题精选(2)

240 阅读5分钟

前言

今天已经是3月5号了,春招时间贵如油,今天依旧带大家来速通春招面试题。这里是上一期,没看前面的同学可以看一下三月份了,又到了春招的季节,该开始准备面试了- 掘金 (juejin.cn)

如何实现深浅拷贝

  • 是什么
    面对大部分的问题都可以从是什么开始入手。深浅拷贝通常只针对引用类型。
    • 浅拷贝:只拷贝一层对象,复制这一层对象中的原始值,如果有引用类型的话,就复制他的指针
    • 深拷贝:层层拷贝,所有类型的属性值都会被复制,原对象的修改不会影响拷贝后的对象

    如何实现浅拷贝

    - `for in直接遍历`<br>
    - `Object.assigin({},obj)// 将obj对象拷贝进入空对象中`<br>
    - `newArr = [].concat(arr)// 将数组arr拷贝进空数组中并返回` <br>
    - `newArr = arr.slice()// 将数组arr切片拷贝`<br>
    - `newArr = [...xxx]// 解构原数组拷贝`<br>
    

    手写浅拷贝

// 直接for in遍历
function shallowCopy(obj){ 
    let newObj = {} 
    for(const key in obj){ 
        if(obj.hasOwnProperty(key)){
            // 判断是否是对象的自有属性 newObj[key] = obj[key] 
            } } 
          return newObj }

如何实现深拷贝

  1. 递归层层遍历
function deepCopy(obj) { 
    let newObj = {} 
    for (let key in obj) { 
        if (obj.hasOwnProperty(key)) { 
            if (typeof obj[key] !== 'object' || obj[key] !== null) {
            //判断当前遍历元素是不是对象 
                newObj[key] = obj[key]; 
                    } else {
                    // 不是就递归 newObj[key] = deepCopy(obj[key]); } } } 
            return newObj; }
  1. const newObj = JSON.parse(JSON.stringify(obj))//对象转为字符串再转回对象

这个知识点不再过多赘述,如有同学还有兴趣想深入了解,可以看看我这篇文章,里面还有另外两种深拷贝的方法。面试官:“请你说说深拷贝和浅拷贝”,如何脱颖而出 - 掘金 (juejin.cn)

说说你对闭包的理解

  • 依旧可以从是什么开始入手:当一个函数中的内部函数被外部函数return出去,又因为在js中,内层作用域总是能访问外层作用域的。那么内部函数存在对外部函数的变量的引用,这些变量的集合叫做闭包,就不会被垃圾回收机制销毁。
  • 接着可以说说闭包的优点:
    1. 可以访问外部函数中的变量,可以实现私有属性(全局变量难以维护)
    2. 延长变量的声明周期
    3. 实现柯里化(颗粒化)
  • 缺点:会造成内存泄漏
    调用栈中的变量不会被回收,因为函数执行完毕后,函数的作用域被销毁,但是由于闭包函数内部的变量不会被销毁,因为函数内部的变量被闭包引用,所以函数内部的变量不会被销毁,从而造成内存泄漏。

什么是柯里化?

我们在聊闭包的时候说到了柯里化,面试官就很有可能会往这个方向提问。在面试的时候我们要尽量将面试官往我们熟悉的知识点带,能够引导面试官这样的面试就是最完美的。

其实这个知识点也不长,一句话就能说完: 将一个接受多个参数的函数转变为多个只接受一个参数的函数
这个知识点最难的地方在手写一个柯里化:

function add(a, b, c){
    return a + b + c
}
console.log(add.length);

function curry(fn){
    let judge = (...args) =>{
        if(args.length === fn.length)return fn(...args)
        return (...arg)=>judge(...args,...arg)
    }
    return judge
}

let addCurry = curry(add)
console.log(addCurry(1)(2)(3));

这个curry函数就成功实现了柯里化。

说说你对作用域的理解

其实说到闭包最有可能说到的是这个知识点。上面那个柯里化算是个小插曲,不一定会问。但是关于作用域的问题在面试中是一定会被问到的。

  • 是什么: 作用域定义了变量和函数在程序中被识别和可访问的范围。作用域规则可以帮助确保变量名和函数名不会发生冲突。简单来说就是作用域规定了变量可见的范围,控制了变量的访问权限。
  • 有哪些
    1. 全局作用域:全局作用域中的变量在代码的任何地方都可以被访问
    2. 函数作用域:函数作用域中的变量只能在声明它们的函数内部访问,外部无法访问。这意味着在函数外部无法访问函数内部的变量,但在函数内部可以访问外部的变量。
    3. 块级作用域: {}+let/const 这样的组合就会形成块级作用域,块级作用域中的变量只能在最近的一对花括号,避免使用var带来的声明提升问题

这个地方主要要记住块级作用域,但除此之外还有两个知识点需要了解一下。

作用域链(作用域的访问规则)

作用域只能由内到外的访问,这种访问规则形成的链状关系我们称之为作用域链。

词法作用域

普通的作用域是能够被修改的,但是词法作用域是编译器在编译代码时就确定的,不会改变的。 函数或者变量定义的区域,定义在哪里指向哪里

尾声

这个系列仍然会接着更新的,想要面试又无从下手的可以关注我一下等我更新哦。另外兄弟们点点赞吧,创作不易,兄弟们的每一个赞都是对我的激励。祝兄弟们都能通过面试,轻松拿下大厂。