2020前端最新面经:我又又又又换工作了(答案篇)

前端码头

共 7306字,需浏览 15分钟

 · 2020-12-05




个人答案仅供参考,偏颇之处,欢迎补充及指正

01

js基础:

一、js继承的多种方式以及优缺点?

答案:可参阅这篇文章:

由浅入深:彻底弄懂JS原型与继承

二、阅读以下代码,说出输出结果?

for (var i = 0; i < 5; i++) {    setTimeout(function() {        console.log(i);    }, 1000);}

答案:输出5个5


追问:如果希望按顺序输出01234,应该怎么修改,尽可能写出多种方式?

第一种: for (let i = 0; i < 5; i++) {    setTimeout(function() {       console.log(i);    }, 1000); } 第二种:  for (var i = 0; i < 5; i++) {       (function(j) {          setTimeout(function() {            console.log(j);        }, 1000);       })(i);  }  第三种:  for (var i = 0; i < 5; i++) {     setTimeout(function(j) {        console.log(j);     }, 1000, i);  }

三、说一说事件代理,优缺点是什么?实现原理是什么?


事件代理是指将事件绑定到目标元素的父元素上,利用冒泡机制触发该事件

优点:

  • 可以减少事件注册,节省大量内存占用

  • 可以将事件应用于动态添加的子元素上

缺点:使用不当会造成事件在不应该触发时触发

ulEl.addEventListener('click', function(e){    var target = event.target || event.srcElement;    if(!!target && target.nodeName.toUpperCase() === "LI"){        console.log(target.innerHTML);    }}, false);


四、阅读以下代码,说出输出结果,并解析其原因?

   console.log('a');    setTimeout(function () {        console.log('b');        new Promise(function (resolve) {            console.log('c');            resolve();        }).then(function () {            console.log('d')        })    })    new Promise(function (resolve) {        console.log('e');        resolve();    }).then(function () {        console.log('f')    })

//输出:aefbcd这道题主要考的是Event Loop(事件循环),有不懂的地方,可以阅读这篇文章:面试官常问的Event Loop,你真的懂吗?

02

es6篇:

一、async/await能否单独使用?

async作为一个关键字放到函数前面,async函数执行会返回一个promise对象,并且把内部的值进行promise的封装。如果只是async,  和promise 差不多,但有了await就不一样了, await 关键字只能放到async 函数里面,await是等待的意思。它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果。

所以async可以单独使用,await不能,会报错


二、es6模块化如何使用?

export default  xxximport xxx from './'
export xxximport {xxx} from './'

追问:CommonJS 、 AMD、CMD 模块化的区别?commonJs应用于服务器端,NodeJS是CommonJS规范的实现。AMD、CMD应用于客户端,AMD(异步模块定义)规范, CMD (通用模块定义)规范

三、手写一个promise?

class Promise{  constructor(executor){    // 初始化state为等待态    this.state = 'pending';    // 成功的值    this.value = undefined;    // 失败的原因    this.reason = undefined;    let resolve = value => {      // state改变,resolve调用就会失败      if (this.state === 'pending') {        // resolve调用后,state转化为成功态        this.state = 'fulfilled';        // 储存成功的值        this.value = value;      }    };    let reject = reason => {      // state改变,reject调用就会失败      if (this.state === 'pending') {        // reject调用后,state转化为失败态        this.state = 'rejected';        // 储存失败的原因        this.reason = reason;      }    };    // 如果executor执行报错,直接执行reject    try{      executor(resolve, reject);    } catch (err) {      reject(err);    }  }}
03

浏览器原理篇:

一、说下浏览器垃圾回收机制?

JS的回收机制分两种:1.标记清除 2.引用计数。各大浏览器常用的是前者


二、在浏览器中输入一个网址后,发生了什么?

  • 第一步 浏览器通过DNS查找该域名的 IP 地址

  • 第二步 浏览器根据解析得到的IP地址向 web 服务器发送一个 HTTP 请求

  • 第三步 服务器收到请求并进行处理

  • 第四步 服务器返回一个响应

  • 第五步 浏览器对该响应进行解码,解析html为dom、解析css 为css-tree、dom+ css 生成render-tree 绘图

  • 第六步 页面显示完成后,浏览器发送异步请求。

  • 第七步 整个过程结束之后,浏览器关闭TCP连接。


三、如何最小化重绘和重排?

  • 需要要对元素进行复杂的操作时,可以先隐藏(display:"none"),操作完成后再显示

  • 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document

  • 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流

  • 尽量避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流)

  • 避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)

  • 尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color批量修改元素样式;elem.className 和 elem.style.cssText 代替 elem.style.xxx


四、说一下浏览器缓存机制?

答案:可参阅这篇文章

【前端面试必问】浏览器缓存原理?---送你满分答案

04

http篇:

一、常用的 http 状态码,表达含义是什么?

状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:

  • 1xx:指示信息--表示请求已接收,继续处理

  • 2xx:成功--表示请求已被成功接收、理解、接受

  • 3xx:重定向--要完成请求必须进行更进一步的操作

  • 4xx:客户端错误--请求有语法错误或请求无法实现

  • 5xx:服务器端错误--服务器未能实现合法的请求


常见状态代码、状态描述、说明:

  • 200 OK //客户端请求成功

  • 400 Bad Request //客户端请求有语法错误,不能被服务器所理解

  • 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用

  • 403 Forbidden //服务器收到请求,但是拒绝提供服务

  • 404 Not Found //请求资源不存在,eg:输入了错误的URL

  • 500 Internal Server Error //服务器发生不可预期的错误

  • 503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常


二、post请求常见的数据格式(content-type的几种取值)

  • 1. Content-Type: application/json :请求体中的数据会以json字符串的形式发送到后端

  • 2. Content-Type: application/x-www-form-urlencoded:请求体中的数据会以普通表单形式(键值对)发送到后端

  • 3. Content-Type: multipart/form-data:它会将请求体的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。


三、封装过axios实例吗?大概说一下

这是我简单封装的代码,主要就是请求拦截和响应拦截,全局token的封装以及全局报错提示

import axios from 'axios';const instance = axios.create({    baseURL: "",    timeout: 5000, // 请求超时时间    headers: {        "Access-Control-Allow-Origin": "*"    },});instance.interceptors.request.use(    config=> {      //全局请求头中加token      const token = window.localStorage.getItem('access_token')      token && (config.headers.authorization = `Bearer ${token}`)      return config;    },     error => {        return Promise.reject(error);    });//响应拦截器instance.interceptors.response.use(   response => {     //根据返回的code值,进行一些业务的处理    const dataAxios = response.data    const {code} = dataAxios    if (code === undefined) {      return dataAxios    } else {      if(code===200||(code>401&&code<500)||code===400){          return dataAxios      }else if(code===401){          if (__CLIENT__) {              cookies.remove('access_token');              cookies.remove('refresh_token');              window.localStorage.removeItem("access_token");              window.localStorage.removeItem("refresh_token");          }else {              errorCreat(`${dataAxios.code}: ${response.config.url}`, dataAxios.code);          }      }else{          errorCreat(`${dataAxios.code}: ${response.config.url}`, dataAxios.code);      }   }   error => {   })export default instance;


、为什么get请求适合缓存,而post请求不适合

get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存

05

webpack篇:

一、是否使用过priofill?

babel-polyfill:(解决浏览器不支持es6的问题)

使用方法:1 npm i babel-polyfill --save2 在main.js中 import ‘babel-polyfill’原理就是把es6的语法转换成es5的语法

二、lodaerplugins 的区别?

loader是在打包构建过程中用来处理源文件的(JSX,Scss,vue等),一次处理一个。plugins并不直接操作单个文件,它直接对整个构建过程其作用。

追问:如何实现一个 lodaerplugins

Loader就是⼀个声明式函数,不能⽤箭头函数。拿到源代码,作进⼀步的修饰处理,再返回处理后的源码
module.exports= function(source){  //source就是传递进来的源码  //this.query 就是loader使用时传递进来的options的参数  console.log(source, this ,this.query)  return source.replace('webpack',this.query.name)}
plugin是用来扩展webpack功能,他在构建流程里注入钩子来实现,为webpack带来了很大的灵活性。在webpack运行的生命周期中会广播许多事件,plugin可以监听这些事件,在特定的时刻调用webpack提供的API执行相应的操作。
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {  // 构造器参数,用于传递options  constructor(options) {    console.log("current plugin option is" + JSON.stringify(options))  }  // apply 方法是一个插件所必须的  apply(compiler) {    // compiler 继承自 tapable    // tapable  提供了多种 hooks  https://github.com/webpack/tapable#hook-types    // run      是 AsyncSeriesHook实例 [tapable提供的多种hooks的一种]    compiler.hooks.run.tap(pluginName, compilation => {      console.log('webpack 构建过程开始!');    });  }}
module.exports = ConsoleLogOnBuildWebpackPlugin
06

框架篇:

一、vuecli3配置webpack的地方?

chainWebpack、configureWebpack

二、vue计算属性缓存原理?

这涉及到了vue源码,并不是几句话能解析清楚的,推荐大家看这篇文章。(https://blog.csdn.net/weixin_39843414/article/details/106152585


三、vuex的数据,刷新页面后为空,在哪个阶段重新赋值?

写mutation里面,根页面调用赋值到state


四、vue中怎么重置data?

Object.assign(this.$data, this.$options.data())

五、Vue 组件间通信有哪些方式?

  • props/emit

  • emit/on

  • vuex

  • attrs/listeners

  • provide/inject

  • $parent/$children与ref


六、vue组件中 data 什么时候可以使用对象?

  • 组件复用时所有组件实例都会共享 data,如果 data 是对象的话,就会造成一个组件修改 data 以后会影响到其他所有组件,所以需要将 data 写成函数,每次用到就调用一次函数获得新的数据。

  • 当我们使用 new Vue() 的方式的时候,无论我们将 data 设置为对象还是函数都是可以的,因为 new Vue() 的方式是生成一个根组件,该组件不会复用,也就不存在共享 data 的情况了

07

数据结构和算法:

一、在整数数组 nums 中,是否存在两个下标 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值小于等于 t ,且满足 i 和 j 的差的绝对值也小于等于 ķ 。如果存在则返回 true,不存在返回 false。

示例:

输入: nums = [1,2,3,1], k = 3, t = 0
输出: true

答案:leetcode 220题】【中等】里面有详细的视频讲解可以查阅

var containsNearbyAlmostDuplicate = function(nums, k, t) {  if (k < 0 || t < 0) return false  const getKey = (value) => {    return Math.floor(value / (t + 1))  }  const map = new Map()  let l = 0  while (l < nums.length) {    const key = getKey(nums[l])    if (map.has(key)) {      return true    } else if (map.has(key + 1) || map.has(key - 1)) {      if (map.get(key + 1) - nums[l] <= t) { return true }      if (nums[l] - map.get(key - 1) <= t) { return true }    }    map.set(key, nums[l])    if (l >= k) {      map.delete(getKey(nums[l - k]))    }    l++  }  return false}

二、假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例:

输入:2
输出:2
解释:有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶
答案:leetcode 70题】【简单】里面有详细的视频讲解可以查阅
var climbStairs = function(n) {    const dp = [];    dp[0] = 1;    dp[1] = 1;    for(let i = 2; i <= n; i++) {        dp[i] = dp[i - 1] + dp[i - 2];    }    return dp[n];};
08

项目篇:

项目篇就是一个开放题了,没有任何标准答案,但大家自己写在简历上的项目一定要理解每个技术点。可以从项目的亮点,还有自己遇到过的有代表性的问题及解决方案等方面准备。自己被问到的几个点,贴出来供大家参考下

一、首次加载,优化项目的加载速度

  1. 代码:异步加载、图片懒加载

  2. 提取公共的js,通过cdn的方式引入

  3. 项目打包压缩,gizp

  4. 分割js\和css,  optimization

  5. 浏览器缓存

二、项目中遇到印象最深的一个问题?

三、小程序分包?

小程序包太大了,超过了最大限制,这时候就需要进行分包处理。  

{  "pages": [    "pages/Login/xxxx",  ],  // 这里就是贴入的代码 root\pages值可以任意改  "subpackages":[{                  "root":"packageA",    "pages":[      "pages/Login/bbb",      "pages/Login/ccc",    ]  }],  "window": {    "backgroundTextStyle": "light",    "navigationBarBackgroundColor": "#fff",    "navigationBarTitleText": "WeChat",    "navigationBarTextStyle": "black"  },
注意几点:
  1. 不要引用同级分包的内容包括

  2. tabBar不能分包

  3. 每个分包不要超过2M



愿你遇贵人

面试是一个双向选择的过程,在面试的时候不要把自己当成一个被挑选的弱势者。前端知识杂却多,有时面试结果不理想,不要怀疑自己。只是在某个方面自己还有欠缺,之后补上就可以了。我们不是在祈求别人给我们一份工作,我们只是在找寻一个适合我们的公司。不妄自菲薄更不骄傲自负,整理好心态,你一定能找到适合自己的公司!!!加油啊

c04d6d358ca277e8a1fe423c0051ba76.webp8559f76672f630882a8864ff74269cd3.webp重大消息

前端小班课(2-6人),前端一对一技术解答、面试指导,都可以添加前端码头小助的微信,进行咨询



往期推荐01

2020前端最新面经:我又又又又换工作了

02

28岁程序员郭宇身价过亿从字节跳动退休,又是心态蹦了的一天?

03

五周从萌新到前端工程师


觉得有用

记得点个在看哦~???

浏览 16
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报