likes
comments
collection
share

[前端面试题总结] ⭐️ 从莉莉丝到滴滴--我的成长之路

作者站长头像
站长
· 阅读数 13

前言

距离上篇面试题的分享已经过去半个月了,经历了面试官的灵魂拷问,笔者也在这半个月收获、成长了许多,所以笔者在本篇文章将会分享几家公司实习岗位的面试题(包括莉莉丝、哈啰、滴滴),希望对大家有帮助~ 一起进步哦~

面经分享

莉莉丝 凉经

莉莉丝是一家游戏公司,所以考察相对来说更注重思维能力,面试官会比较积极的引导,答不出来面试官也会讲解一遍。
  • 瀑布流列表对于请求过的数据是否做优化?了解虚拟滚动(虚拟列表)吗?

    这题是基于我的项目介绍问的。虚拟列表是在处理用户滚动时,只改变列表在可视区域的渲染部分,它可以提高页面渲染性能,减少数据过多时的卡顿。

下面是一个简单的虚拟列表demo:

    function FixedSizeList(props){
        const {{containerHeight,itemCount,itemHeight}} = props; // 容器高度,列表数量,列表项高度
        const [scrollTop,setScrollTop] = useState(0)
        const items = [];
        // 渲染列表第一个index
        let startIdx = Math.floor(scrollTop / itemHeight);
        // 渲染列表最后一个index
        let endIdx = Math.floor((scrollTop+containerHeight)/itemHeight);
        // 在可视区外缓存列表项数量
        const paddingCount = 2;
        startIdx = Math.max(startIdx - paddingCount,0);
        endIdx = Math.min(endIdx + paddingCount,itemCount-1)

        for(let i = startIdx;i <= endIdx;i++) {
            items.push(<Component key={i} index={i}
                    style={{height:itemHeight}}/>)
        }   
        const top = startIdx * itemHeight;
        const contentHeight = itemHeight * itemCount; 

        return (
            <div style={{height:containerHeight,overflow:'auto'}}
                onScroll={
                    (e) => {
                        // 处理渲染有导致的白屏问题
                        // 改为同步更新
                        flushSync(() => {
                            setScrollTop(e.target.scrollTop)
                        })
                    }
                }
            >
                <div style={{height:contentHeight}}>
                    <div style={{height:top}}></div>
                    {items}
                </div>
            </div>
        )
    }

哈啰 已oc

面试官非常年轻,好像就已经是技术专家了,好羡慕,人也很好,整体面下来的感觉还是不错的。

滴滴 已oc

感觉面试官问的问题可回答面比较广,所以可以挑自己擅长的领域说~ 而且面试官比较和蔼,让我不要紧张。面试官直接就跟我约了二面的时间。
  • css布局方式

    说了以下四种布局方式,然后以水平垂直居中为例,具体的说了下每种布局方式是如何使用的。

    1. flex
    2. grid
    3. float
    4. position
  • float离开文档流怎么做处理

    我大概说了下清浮动、高度塌陷的不同处理方式,顺便说了下BFC

  • position属性,分别相对谁定位,具体使用场景

  • js 数据类型 Symbol使用场景

  • 类型判断方法

    我说了三种 typeOf、instanceOf、Object.prototype.toString.call() 以及他们各自的优缺点 面试官接着问了instanceOf 原理,说完继续问了下面两个问题 Array instanceOf Array == ?(false) Object instanceOf Object == ?(true)

  • 数组api,以及在项目使用场景

  • forEach map区别 使用场景

    • forEachmap都可以对数组的进行遍历。
    • forEach返回值为undefined,所以不能进行链式调用,适用于不更改数组的情况;
    • map会返回一个新数组,这个新数组由原数组中的每个元素都调用一次提供的callbackFn函数后的返回值组成。一般用于需要修改数组的情况。
    • 对于数组项是基本数据类型的数组,forEachmap都不修改调用它的原数组本身,但是那个数组可能会被 callbackFn 函数改变; 对于数组项是引用数据类型的数组,用forEachmap都可以改变它的属性值。

    又问:给对象数组中对象的每一项加一个属性,用 forEach 还是 map? 这里用forEach会更好,直接在原数组上修改即可,如果用map,还要将返回的结果重新赋值给原来的数组变量,语义不好。

  • 手写代码 将对象数组转为对象

        const array = [
        {
        code: 101,
        name: '北京',
        },
        {
        code: 102,
        name: '石家庄',
        },
        {
        code: 102,
        name: '江苏',
        children: [{
            code: 102,
            name: '南京',
        },{
            code: 102,
            name: '连云港',
        }]
        }
    ]
    

    转换成:

      {
        '北京':{
          code: 101,
          name: '北京'
        },
        '石家庄':{
           code: 102
           name: '石家庄'
        },
        '南京':{
           code: 102
           name: '南京'
        },
        '连云港':{
           code: 102
           name: '连云港'
        }
      }
    

    实现代码:

    function toObj(arr) {
        let obj = {};
        for(let item of arr) {
            if(item['children']!==undefined) {
                obj = {...toObj(item['children']),...obj};
            }else {
                obj[item.name]=item;
            }
    
        }
        return obj;
    }
    
  • 根据代码看输出 this问题

    const obj1 = {
        hello: function () {
            console.log(this);   // obj1
            setTimeout(function () {
                console.log(this);   // window
            });
        }
    }
    obj1.hello();
    
    
    const obj2 = {
        hello: function () {
            console.log(this);   // obj2
            setTimeout(() => {
                console.log(this);   // obj2
            });
        }
    }
    obj2.hello()
    
    const obj3 = {
        hello: ()=> {
            console.log(this);   // wondow
            setTimeout(() => {
                console.log(this);    // window
            });
        }
    }
    obj3.hello()
    
  • 闭包 以及项目中的使用

  • 防抖节流

  • vite webpack 了解多少

  • js模块化 commonjs esmodule区别

  • UMD AMD CMD

    • AMD (Asynchronous Module Definition 异步模块定义) commonjs是同步加载的,不适用于浏览器环境,所有有了AMD CMD; AMD是异步加载的,模块的加载不影响后面语句的运行。所有依赖这个模块的语句都定义在一个回调函数中,等 加载完之后,这个回调才会运行。AMD 的模块引入由 define 方法来定义
    • CMD (Common Module Definition) 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。CMD 推崇依赖就近,AMD 推崇依赖前置。
    • UMD (Universal Module Definition 通用规范模块) 统一浏览器端(AMD)和非浏览器端(commonjs)的模块化方案。
      1. 先判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块;
      2. 再判断是否支持commonjs(exports是否存在),存在则使用commonjs模块格式
      3. 前两个都不存在,则将模块公开到全局
  • 浏览器缓存 怎么做demo的

    主要针对的是前端静态资源(js css image),大大的减少了请求的次数,提高了网站的性能(两端)

    • 强缓存 设置http响应头
      1. http1.0版本:Expires 具体时间点,客户端时间不准可能会导致误差
      2. http1.1版本:Cache-Control:max-age=xxx 时间偏移量 倒计时
    • 协商缓存
      • Last-Modified 会经常更改的数据,不变则发送304。请求数量不变,请求体积减小
        1. 设置响应头:Last-Modified 文件最近更改时间
        2. 判断请求头:if-modified-since == Last-Modified 发送304
      • etag 根据文件生成哈希串
        1. 设置响应体:Etag
        2. 判断请求头:if-none-match == Etag 发送304
  • nginx

  • 跨域 jsonp缺点

  • 项目后端做了啥

  • 异步并行/串行 问 异步事件1、异步事件2是并行还是串行?怎么变为并行?

        async() {
            await 异步事件1
            await 异步事件2
        }
    

    这里我说的是让异步事件不写在await后面,这是一种实现方式。当然还有更好的实现方式,所以面试官问了下一题。

    async ()=>{ 
        let result1 = 异步事件1
        let result2 =  异步事件2
        let res1 = await result1
        let res2 = await result2
        console.log(res1,res2)
    }
    
  • promose.all 和 promise.allSettled

    先说怎么用promise.all解决上一题吧

    async ()=>{ 
        var result = await Promise.all([异步事件1,异步事件2]) 
        console.log(result[0],result[1])
    }
    

    这么写确实可以解决上题的问题,但是在promise.all中如果有一个异步事件出错,那么将会返回一个失败的promise。所以如果异步事件互不依赖的话使用promise.allSettled可能会更好,无论每个异步事件执行成功或失败都会返回一个带有执行结果的promise。 > 想了解更多更多promise.allSettled可以看这里~

        async ()=>{ 
            var result = await promise.allSettled([异步事件1,异步事件2]) 
            console.log(result[0],result[1])
        }
    

最后