8月最新:4个前端精选面试题(含答案&解析)

     

        网上的面试题一大堆,鱼龙混杂,一方面多数题目质量不高,另一方面有答案的很少,即使拿到面试题对自己的帮助也不大。

        最近我花了一点时间,为大家整理了8月面试的过程中遇到的4个值得分享的前端面试题,内容包括Vue、React、JavaScript、Webpack等前端知识点和相关面试题,重点是每道题都有非常详细的答案和解析。

1.Vue v-model 是如何实现的,语法糖实际是什么

公司:脉脉

分类:Vue

答案&解析????????????

一、语法糖

指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。糖在不改变其所在位置的语法结构的前提下,实现了运行时的等价。可以简单理解为,加糖后的代码编译后跟加糖前一样,代码更简洁流畅,代码更语义自然.

二、实现原理

1.作用在普通表单元素上

动态绑定了 input 的 value 指向了 messgae 变量,并且在触发 input 事件的时候去动态把 message 设置为目标值

<input v-model="sth" />
//  等同于
<input 
    v-bind:value="message" 
    v-on:input="message=$event.target.value"
>
//$event 指代当前触发的事件对象;
//$event.target 指代当前触发的事件对象的dom;
//$event.target.value 就是当前dom的value值;
//在@input方法中,value => sth;
//在:value中,sth => value;
2.作用在组件上

在自定义组件中,v-model 默认会利用名为 value 的 prop 和名为 input 的事件

本质是一个父子组件通信的语法糖,通过prop和$.emit实现

因此父组件v-model语法糖本质上可以修改为  <child :value="message" @input="function(e){message = e}"></child>

在组件的实现中,我们是可以通过 v-model属性 来配置子组件接收的prop名称,以及派发的事件名称。

例子

// 父组件
<aa-input v-model="aa"></aa-input>
// 等价于
<aa-input v-bind:value="aa" v-on:input="aa=$event.target.value"></aa-input>

// 子组件:
<input v-bind:value="aa" v-on:input="onmessage"></aa-input>

props:{value:aa,}
methods:{
    onmessage(e){
        $emit( input ,e.target.value)
    }
}

默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event

但是一些输入类型比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。使用 model 选项可以回避这些情况产生的冲突。

js 监听input 输入框输入数据改变,用oninput ,数据改变以后就会立刻触发这个事件。

通过input事件把数据$emit 出去,在父组件接受。

父组件设置v-model的值为input$emit过来的值。

2.React 中 setState 后发生了什么?setState 为什么默认是异步?setState 什么时候是同步?

公司:微医

分类:React

答案&解析????????????

一、React中setState后发生了什么

在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。

经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。

在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。

在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

二、setState 为什么默认是异步

假如所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,多次setState),都重新vnode diff + dom修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个setState合并成一次组件更新。

三、setState 什么时候是同步

在setTimeout或者原生事件中,setState是同步的。

3.多个 tab 只对应一个内容框,点击每个 tab 都会请求接口并渲染到内容框,怎么确保频繁点击 tab 但能够确保数据正常显示?

公司:爱范儿

分类:JavaScript

答案&解析????????????

一、分析

因为每个请求处理时长不一致,可能会导致先发送的请求后响应,即请求响应顺序和请求发送顺序不一致,从而导致数据显示不正确。

即可以理解为连续触发多个请求,如何保证请求响应顺序和请求发送顺序一致。对于问题所在场景,用户只关心最后数据是否显示正确,即可以简化为:连续触发多个请求,如何保证最后响应的结果是最后发送的请求(不关注之前的请求是否发送或者响应成功)

类似场景:input输入框即时搜索,表格快速切换页码

二、解决方案

防抖(过滤掉一些非必要的请求) + 取消上次未完成的请求(保证最后一次请求的响应顺序)

取消请求方法:

  • XMLHttpRequest 使用 abort api 取消请求

  • axios 使用 cancel token 取消请求

伪代码(以 setTimeout 模拟请求,clearTimeout 取消请求)

/**
 * 函数防抖,一定时间内连续触发事件只执行一次
 * @param {*} func 需要防抖的函数
 * @param {*} delay 防抖延迟
 * @param {*} immediate 是否立即执行,为true表示连续触发时立即执行,即执行第一次,为false表示连续触发后delay ms后执行一次
 */
let debounce = function(func, delay = 100, immediate = false) {
  let timeoutId, last, context, args, result

  function later() {
    const interval = Date.now() - last
    if (interval < delay && interval >= 0) {
      timeoutId = setTimeout(later, delay - interval)
    } else {
      timeoutId = null
      if (!immediate) {
        result = func.apply(context, args)
        context = args = null
      }
    }
  }

  return function() {
    context = this
    args = arguments
    last = Date.now()

    if (immediate && !timeoutId) {
      result = func.apply(context, args)
      context = args = null // 解除引用
    }
    
    if (!timeoutId) {
      timeoutId = setTimeout(later, delay)
    }

    return result
  }
}


let flag = false   // 标志位,表示当前是否正在请求数据
let xhr = null

let request = (i) => {
    if (flag) {
        clearTimeout(xhr)
        console.log(`取消第${i - 1}次请求`)
    }
    flag = true
    console.log(`开始第${i}次请求`)
    xhr = setTimeout(() => {
        console.log(`请求${i}响应成功`)
        flag = false
    }, Math.random() * 200)
}

let fetchData = debounce(request, 50)  // 防抖

// 模拟连续触发的请求
let count = 1 
let getData = () => {
  setTimeout(() => {
    fetchData(count)
    count++
    if (count < 11) {
        getData()
    }
  }, Math.random() * 200)
}
getData()

/* 某次测试输出:
    开始第2次请求
    请求2响应成功
    开始第3次请求
    取消第3次请求
    开始第4次请求
    请求4响应成功
    开始第5次请求
    请求5响应成功
    开始第8次请求
    取消第8次请求
    开始第9次请求
    请求9响应成功
    开始第10次请求
    请求10响应成功
*/

4.Webpack 为什么慢,如何进行优化

分类:工程化

答案&解析????????????

一、webpack 为什么慢

webpack是所谓的模块捆绑器,内部有循环引用来分析模块间之间的依赖,把文件解析成AST,通过一系类不同loader的加工,最后全部打包到一个js文件里。

webpack4以前在打包速度上没有做过多的优化手段,编译慢的大部分时间是花费在不同loader编译过程,webpack4以后,吸收借鉴了很多优秀工具的思路,

如支持0配置,多线程等功能,速度也大幅提升,但依然有一些优化手段。如合理的代码拆分,公共代码的提取,css资源的抽离

二、优化 Webpack 的构建速度

  • 使用高版本的 Webpack (使用webpack4)

  • 多线程/多实例构建:HappyPack(不维护了)、thread-loader

  • 缩小打包作用域:

    • exclude/include (确定 loader 规则范围)

    • resolve.modules 指明第三方模块的绝对路径 (减少不必要的查找)

    • resolve.extensions 尽可能减少后缀尝试的可能性

    • noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)

    • IgnorePlugin (完全排除模块)

    • 合理使用alias

  • 充分利用缓存提升二次构建速度:

    • babel-loader 开启缓存

    • terser-webpack-plugin 开启缓存

    • 使用 cache-loader 或者 hard-source-webpack-plugin 注意:thread-loader 和 cache-loader 兩個要一起使用的話,請先放 cache-loader 接著是 thread-loader 最後才是 heavy-loader

  • DLL

    • 使用 DllPlugin 进行分包,使用 DllReferencePlugin(索引链接) 对 manifest.json 引用,让一些基本不会改动的代码先打包成静态资源,避免反复编译浪费时间。

三、使用Webpack4带来的优化

  • V8带来的优化(for of替代forEach、Map和Set替代Object、includes替代indexOf)

  • 默认使用更快的md4 hash算法

  • webpack AST可以直接从loader传递给AST,减少解析时间

  • 使用字符串方法替代正则表达式

来看下具体使用

1.noParse
  • 不去解析某个库内部的依赖关系

  • 比如jquery 这个库是独立的, 则不去解析这个库内部依赖的其他的东西

  • 在独立库的时候可以使用

module.exports = {
  module: {
    noParse: /jquery/,
    rules:[]
  }
}
2.IgnorePlugin
  • 忽略掉某些内容 不去解析依赖库内部引用的某些内容

  • 从moment中引用 ./local 则忽略掉

  • 如果要用local的话 则必须在项目中必须手动引入 import moment/locale/zh-cn

module.exports = {
  plugins: [
    new Webpack.IgnorePlugin(/./local/, /moment/),
  ]
}
3.dillPlugin
  • 不会多次打包, 优化打包时间

  • 先把依赖的不变的库打包

  • 生成 manifest.json文件

  • 然后在webpack.config中引入

  • webpack.DllPluginWebpack.DllReferencePlugin

4.happypack -> thread-loader
  • 大项目的时候开启多线程打包

  • 影响前端发布速度的有两个方面,一个是 构建 ,一个就是 压缩 ,把这两个东西优化起来,可以减少很多发布的时间。

5.thread-loader

thread-loader 会将您的 loader 放置在一个 worker 池里面运行,以达到多线程构建。

把这个 loader 放置在其他 loader 之前,放置在这个 loader 之后的 loader 就会在一个单独的 worker 池(worker pool)中运行。

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /.js$/,
        include: path.resolve("src"),
        use: [
          "thread-loader",
          // 你的高开销的loader放置在此 (e.g babel-loader)
        ]
      }
    ]
  }
}

每个 worker 都是一个单独的有 600ms 限制的 node.js 进程。同时跨进程的数据交换也会被限制。请在高开销的loader中使用,否则效果不佳。

来的值。


最后,我想说现在的前端面试,难度越来越大,跟五六年前已经完全不能比了。尤其是大厂,进入的门槛非常高。普通程序员只能靠“海投简历”,增加面试机会,来提高求职成功率。

如果你在面试中也遇到这些情况:

  • 1.简历写的一塌糊涂,想去大厂连简历都过不了关

  • 2.面试前不知道该如何梳理知识点

  • 3.面试不会“避坑”,失败都不知道为什么

推荐一个优质课程给你——《大厂前端面试全攻略》

课程中,前端大佬带你剖析大厂面试流程,遍历前端面试知识技能,让你更高效更全面的进行面试准备。内容包含建立知识体系、全面升级代码、面试细节剖析等接地气的面试攻略,只为帮你省时省力准备面试,让你面试如虎添翼,三步带你秒变offer收割机。

只需扫描下图二维码,领取优惠券,0.02元即可报名该课程。

前50位添加好友的同学,再免费送原价98元的《面试高频考点专题课》。

????????????

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值