2020前端最新面经:我又又又又换工作了(答案篇)
共 7306字,需浏览 15分钟
·
2020-12-05 08:33
个人答案仅供参考,偏颇之处,欢迎补充及指正
01js基础:
一、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,你真的懂吗?
02es6篇:
一、async/await能否单独使用?
async作为一个关键字放到函数前面,async函数执行会返回一个promise对象,并且把内部的值进行promise的封装。如果只是async, 和promise 差不多,但有了await就不一样了, await 关键字只能放到async 函数里面,await是等待的意思。它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果。
所以async可以单独使用,await不能,会报错
二、es6模块化如何使用?
export default xxx
import xxx from './'
export xxx
import {xxx} from './'
追问:CommonJS 、 AMD、CMD 模块化的区别?commonJs应用于服务器端,NodeJS是CommonJS规范的实现。AMD、CMD应用于客户端,AMD(异步模块定义)规范, CMD (通用模块定义)规范
三、手写一个promise?
03class 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);
}
}
}
浏览器原理篇:
一、说下浏览器垃圾回收机制?
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
四、说一下浏览器缓存机制?
答案:可参阅这篇文章
04http篇:
一、常用的 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请求适合于请求缓存
05webpack篇:
一、是否使用过priofill?
babel-polyfill:(解决浏览器不支持es6的问题)
使用方法:1 npm i babel-polyfill --save2 在main.js中 import ‘babel-polyfill’原理就是把es6的语法转换成es5的语法
二、
lodaer
与 plugins
的区别?
loader是在打包构建过程中用来处理源文件的(JSX,Scss,vue等),一次处理一个。plugins并不直接操作单个文件,它直接对整个构建过程其作用。
追问:如何实现一个 lodaer
和plugins
?
Loader就是⼀个声明式函数,不能⽤箭头函数。拿到源代码,作进⼀步的修饰处理,再返回处理后的源码
module.exports= function(source){
//source就是传递进来的源码
//this.query 就是loader使用时传递进来的options的参数
console.log(source, this ,this.query)
return source.replace('webpack',this.query.name)
}
06plugin是用来扩展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
框架篇:
一、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
的情况了
数据结构和算法:
一、在整数数组 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题】【简单】里面有详细的视频讲解可以查阅08var 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];
};
项目篇:
项目篇就是一个开放题了,没有任何标准答案,但大家自己写在简历上的项目一定要理解每个技术点。可以从项目的亮点,还有自己遇到过的有代表性的问题及解决方案等方面准备。自己被问到的几个点,贴出来供大家参考下一、首次加载,优化项目的加载速度
代码:异步加载、图片懒加载
提取公共的js,通过cdn的方式引入
项目打包压缩,gizp
分割js\和css, optimization
浏览器缓存
二、项目中遇到印象最深的一个问题?
三、小程序分包?
小程序包太大了,超过了最大限制,这时候就需要进行分包处理。
注意几点:{
"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"
},
不要引用同级分包的内容包括
tabBar不能分包
每个分包不要超过2M
愿你遇贵人
面试是一个双向选择的过程,在面试的时候不要把自己当成一个被挑选的弱势者。前端知识杂却多,有时面试结果不理想,不要怀疑自己。只是在某个方面自己还有欠缺,之后补上就可以了。我们不是在祈求别人给我们一份工作,我们只是在找寻一个适合我们的公司。不妄自菲薄更不骄傲自负,整理好心态,你一定能找到适合自己的公司!!!加油啊
重大消息前端小班课(2-6人),前端一对一技术解答、面试指导,都可以添加前端码头小助的微信,进行咨询
往期推荐0102
28岁程序员郭宇身价过亿从字节跳动退休,又是心态蹦了的一天?
觉得有用
记得点个在看哦~???