原因
我在半年前入职xxxx,遇见了我的贵人,6年前端经验的程序员,具体信息不多说,从我入公司就是跟在他屁股后面学习,基本有问必答对我前端技术的提升简直可以用外挂形容,最近公司动荡不用说,基本各位公司多少都得晃两下,然后师傅也和上司有点摩擦,基本俩人在场,那气氛都是肉眼可见的尴尬,不过我师傅人家大业大,来前端工作我怀疑都有些体验生活的味道,送别师傅的同时,转头给我扔了【好些文件】,说,这是在公司最后一次帮你,以后生活上,有事别找我,没事可以唠唠,带你一段时间了,懂点事,我是出去玩的,别因为一点Bbug找我...
文件
有点多只截了一部分
展示内容1-面试题
第 1 题:写 React / Vue 项目时为什么要在列表组件中写 key, 其作用是什么?
key 是给每一个 vnode 的唯一 id,可以依靠 key,更准确,更快的拿到 oldVnode 中对 应的 vnode 节点
第 2 题:['1', '2', '3'].map(parseInt) what & why ?
第一眼看到这个题目的时候,脑海跳出的答案是 [1, 2, 3],但是真正的答案是[1, NaN, NaN]。
首先让我们回顾一下,map 函数的第一个参数 callback。这个 callback 一共可以 接收三个参数,其中第一个参数代表当前被处理的元素,而第二个参数代表该 元素的索引。
arr.map(callback: (value: T, index: number, array: T[]) => U, thisArg?: any);
而 parseInt 则是用来解析字符串的,使字符串成为指定基数的整数。接收两个 参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。
parseInt(string, radix)
了解这两个函数后,我们可以模拟一下运行情况
parseInt('1', 0) //radix 为 0 时,且 string 参数不以“0x”和“0”开头时,
按照 10 为基数处理。这个时候返回 1parseInt('2', 1) //基数为 1(1 进制)表示的数中,最大值小于 2,所以无法解析,返回 NaNparseInt('3', 2) //基数 为 2(2 进制)表示的数中,最大值小于 3,所以无法解析,返回 NaN
第 3 题:什么是防抖和节流?有什么区别?如何实现?
防抖——触发高频事件后 n 秒后函数只会执行一次,如果 n 秒内高频事件再 次被触发,则重新计算时间;
function debounce(fn) {
let timeout = null
// 创建一个标记用来存放定时器的返回值
return function() {
clearTimeout(timeout)
// 每当用户输入的时候把前一个 setTimeout clear 掉
timeout = setTimeout(() => {
// 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的
interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
fn.apply(this, arguments)
}, 500)
}}function sayHi() {
console.log('防抖成功')}var inp =
document.getElementById('inp')inp.addEventListener('input',
debounce(sayHi)) // 防抖
节流——高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执
行频率。
function throttle(fn) {
let canRun = true // 通过闭包保存一个标记
return function() {
if (!canRun) return
// 在函数开头判断标记是否为 true,不为 true 则 return
canRun = false // 立即设置为 false
setTimeout(() => {
// 将外部传入的函数的执行放在 setTimeout 中
fn.apply(this, arguments)
// 最后在 setTimeout 执行完毕后再把标记设置为 true(关键) 表
示可以执行下一次循环了。当定时器没有执行的时候标记永远是 false,在开头
被 return 掉
canRun = true
}, 500)
}}function sayHi(e) {
console.log(e.target.innerWidth,
e.target.innerHeight)}window.addEventListener('resize',
throttle(sayHi))
第 4 题:介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
Set——对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用
WeakSet——成员都是对象;成员都是弱引用,可以被垃圾回收机制回收,可以 用来保存 DOM 节点,不容易造成内存泄漏;
Map——本质上是键值对的集合,类似集合;可以遍历,方法很多,可以跟各 种数据格式转换。
WeakMap——只接受对象最为键名(null 除外),不接受其他类型的值作为键 名;键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收, 此时键名是无效的;不能遍历,方法有 get、set、has、delete。
第 5 题:介绍下深度优先遍历和广度优先遍历,如何实现?
深度优先遍历——是指从某个顶点出发,首先访问这个顶点,然后找出刚访问 这个结点的第一个未被访问的邻结点,然后再以此邻结点为顶点,继续找它的 下一个顶点进行访问。重复此步骤,直至所有结点都被访问完为止。
广度优先遍历——是从某个顶点出发,首先访问这个顶点,然后找出刚访问这 个结点所有未被访问的邻结点,访问完后再访问这些结点中第一个邻结点的所 有结点,重复此方法,直到所有结点都被访问完为止。
//1.深度优先遍历的递归写法 function deepTraversal(node) {
let nodes = []
if (node != null) {
nodes.push[node]
let childrens = node.children
for (let i = 0;
i < childrens.length; i++) deepTraversal(childrens[i])
} return nodes}
//2.深度优先遍历的非递归写法 function deepTraversal(node) {
let nodes = []
if (node != null) {
let stack = []
//同来存放将来要访问的节点
stack.push(node)
while (stack.length != 0) {
let item = stack.pop()
//正在访问的节点
nodes.push(item)
let childrens = item.children
for (
let i = childrens.length - 1;
i >= 0;
i--
//将现在访问点的节点的子节点存入 stack,供将来访问
)
stack.push(childrens[i])
}
}return nodes}
//3.广度优先遍历的递归写法 function wideTraversal(node) {
let nodes = [],
i = 0
if (node != null) {
nodes.push(node)
wideTraversal(node.nextElementSibling)
node = nodes[i++]
wideTraversal(node.firstElementChild)
}
return nodes}//4.广度优先遍历的非递归写法 function
wideTraversal(node) {
let nodes = [],
i = 0 while (node != null) {
nodes.push(node)
node = nodes[i++]
let childrens = node.children
for (let i = 0;
i < childrens.length;
i++) {
nodes.push(childrens[i])
}
}
return nodes
}
第 11 题:算法手写题
已知如下数组,编写一个程序将数组扁平化去并除其中重复部分数据,最终得 到一个升序且不重复的数组
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
答:使用 Set 方法去重,flat(Infinity)扁平化
Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
第 12 题:JS 异步解决方案的发展历程以及优缺点。
1、回调函数(callback)
优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队 等着,会拖延整个程序的执行。)
缺点:回调地狱,不能用 try catch 捕获错误,不能 return
2、Promise
优点:解决了回调地狱的问题
缺点:无法取消 Promise ,错误需要通过回调函数来捕获
3、Generator
特点:可以控制函数的执行,可以配合 co 函数库使用
4、Async/await
优点:代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题
缺点:await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使 用 await 会导致性能上的降低。
实践题
经过二个月“测评项目“开发,测试,上线,”测评项目“服务于学校实施的第一 站,参与测评学校的学生上午 8 点集中开测。市场反馈有如下情况:
1)打开网站出现 502
2)登录进不去系统
3)提交数据一致反复
4)有时出现白屏现象
对于市场反馈情况谈谈你的认识?
首先,502 错误,意思是 worker 忙不过来,参与测评学校的学生上午 8 点集中开测,在 短时间内访问人数过多导致积累了大量的请求,后台服务器忙不过来。解决方法贵公司可以 看一下 PHP 到底在忙些啥,如果是 CPU 密集型计算(应该不会),看看 CPU 和内存满没满, 没满就多开一些 worker,满了就多加一些机子。我猜测可能是数据库响应缓慢,然后人多了 数据库是否能撑住也是一个考虑,多用一些缓存吧。防流量攻击真没啥好办法,找牛逼一些的机房/CDN 吧。
第二个问题,结合 502 报错来看,登录不进系统的原因估计也是短时间内访问人数过多导致服务器崩了。提交数据一直反复就相对复杂了,可能出现的使用场景也有很多。
比如说我们在提交表单的时候,有可能是网络延迟或内存不足,导致点击一次提交按钮, 页面没有反应,结果强迫症就犯了,就疯狂的点提交恨不得把手机屏幕点烂来。也有可能是
有些毛孩子,点完提交按钮立马点击刷新页面,或直接返回上层页面想卡 bug,不为别的, 哎~就是玩儿。
对于这种情况,我以前工作的做法就是设置蒙版层,不管你怎么点,只要你点提交,我 就给你弹出蒙版层。其实这个问题最根本的原因是程序没有进行重复判断,导致数据库重复 写入。前端后端都可以添加一个重复判断逻辑,判断后台数据库中是否已经存在当前提交的 数据,避免重复添加。但是这种判断只解决了两次表单依次提交的问题,如果不同用户同时 提交表单,数据就不一定会正确了。这种问题就是我们常说的并发问题,并发问题的解决方 案也有很多,比如:加锁排队处理等。
最后提到解决白屏问题,我个人在白屏优化实践上尝试过 SSR、预渲染、还有骨架屏等 一些方案,每个方案都个有自己的优劣,需要根据实际的业务场景进行取舍。 SSR 服务端渲染,这个方案可以让页面直接在服务端渲染,但是不利于前后端分离,开 发的效率也比客户端渲染低,同时也加大了服务器的压力。而且由于地理位置的不同,不同 用户看到的页面也是不一样的,也就是所谓的千人千面,这也为缓存造成了一定困难。
使用预渲染的话,预渲染插件会在编译阶段就将对应的路由编译好插入到 app 节点,这 样就能在 js 文件解析过程中有内容展示,js 解析完成后,项目使用的单页面应用框架会将 app 节点内的内容替换成它渲染好的内容。但是当真实访问页面的时候,真实数据可能已经 和预渲染的数据有了很大的出入,会导致涉及到一些价格、金额、地理位置的地方甚至会导 致用户做出一些错误的决定。
使用骨架屏的话,实现原理和预加载类似,也可以很好的完善预渲染的不足。但是也存 在与业务深度耦合,页面复杂度变高的问题。当应对需求变更时,骨架屏结构成本,工具实 现成本,配置成本,项目的维护成本,都比较高。
二、项目中的挑战 ★★★
★★★ 项目开发中有遇到什么挑战没?
1.问题描述:1)简单介绍这个项目规模、背景 2)什么情况下遇到什么样的问 题
2.你处理这个问题的过程及结果:1)遇到问题你如何思考;2)你如何执行的;
3)处理结果如何
3.通过处理这个问题,你学到了什么或者说通过这个问题,你看到了你们什么 不足,后续动作(采用什么样的方式,在以后的项目中避免再出现这类问题)
1.(使用缓存处理)
在做 Vue 开发移动端 APP 时,有个页面比较常见,左边是对所有菜谱品类的展示,右边 是对对应菜谱的展示,一开始在开发的时候没注意,就直接在 mounted()前面使用 async,里面使用 await 调了两边接口后,又通过 watch 监听了品类索引变化,调了一遍接口。后面发现每次切换品类时,页面都有一闪而过的感觉,发现每次都调了一遍接口,这对性能消耗 挺大。所以就尝试的走了 Vuex 做缓存处理。当时解决这个缓存问题用了一些巧妙的方法,首 先缓存的数据,采用的是对象形式,不是数组。这样写起来更快,因为用品类的下标直接做 缓存数据的 key 值,非常好写。不过后面又有点坑,就是我监听的是引用数据类型,不管是 vue 还是 react,引用数据类型发生变化时,页面可能不会更新。后面又在 mutation 中对 vuex 中的数据更新时,做了一下深复制,就做好了缓存处理。因为我是根据判断这个对象中 有没有数据去调接口的,如果存在,就不调接口。现在做了缓存没错,那如果以后后台的数 据发生了变化的话,那我这里也不调接口了,后台数据就没有在页面上实现更新,所以在跳
出这个页面的时候还要清下缓存。清缓存要在生命周期结束的时候清,如果碰到了动态组件 把 APP 页面下的 Tap 栏包住的时候, Keep-alive。就不能用 destroyed 生命周期清除, 要用 deactivated 生命周期去清除。这样才有始有终,完成缓存处理。
2.(解决关键词高亮问题---->原理和字符串敏感词替换一样,但是用在关键词高亮上算是 一个技术亮点吧)
用户配置一堆关键词,在页面上将这些关键词高亮,也许你会觉得这有什么难度?用正则匹配一下出来高亮不就行了吗?但是,一开始,用户的词不多,我确实使用的是遍历,时间复杂度为 n2。后来用户会配置 100w 量级的词,使用遍历就会使页面卡死崩溃。解决的方法就是:优化性能,高亮分三步,生成字典树,遍历页面文字,取出文字进行匹配。使用字典树代替遍历,整个页面 100w 量级的词绘制可以实现在 1 秒以内。
3.(封装自定义组件)
在一个小程序项目需求中,要求页面头部 tab 栏切换的同时,对应 tab 栏品类的页面也要展示出来。你可能会觉得这个需求用个 taroUI 组件库中的 tabs 标签页组件不就可以完成吗?但是这个需求想满足用户的沉浸式体验,切换页面时需要有独特丝滑的专场特效。所以当时面临的问题就是,使用的 UI 库的组件默认样式生硬,满足不了需求。我当时是对小程序原生 swiper 组件进行了二次封装,主要实现了几点自定义需求:头部 Tab 栏品类样式使用 flex 动态布局,实现品类数量可变;使用 slot 插槽来动态渲染 Tab 区块中的内容,配合 原生 swiper 组件使用定义插槽;小程序原生组件<swiper>是有默认高度的,必须手动设置 其高度,这里使用 wx.getSystemInfo 来动态获取屏幕尺寸。自己封装组件,踩了不少坑, 但从中我学习到了:使用小程序的原生组件,并修改其默认的样式;学会使用 slot 插槽, 实现组件内容的差异化;学会了使用小程序原生 api 获取手机信息,用 js 改变组件样式等等
4.(遇到了难用的轮子)
在写 XXX 小程序项目中需要实现音频播放的功能,官方已经推荐使用新的 API 了,然而 这个小程序官方文档文档写得并不好,很多时候我们会遇到一些需求,或者改变而这些需求 文档里又写得非常模糊,这就比较头疼了。小程序官方文档更新十分频繁,坑非常多。所以 很多时候,我就要去不断地从文档的字里行间猜测,并结合源码一步一步地去跟踪,去尝试 解决这个音频播放问题。但有时候确实超出了我的能力范围,那么我就会把我的问题提炼成 一个小 demo,到知乎、segmentfault 思否去问,或者提问一些同样用这个轮子的作者,最终找到了新 API 的使用规范。
注意:这个时候你就要说你最擅长的,一定是你最擅长的点,告诉他这个问题 怎么解决,一定是你最懂的,而且经得起推敲的解决方案。你要准备的不仅仅是你的项目中有哪些难点,更重要的是和这个难点相关的知识都要准备充分。
所以,你的答案并不是这个项目中最难的点,而是一个最能让你回答好整套相关问题的难点。
三、最难得项目 ★★★ (同上)
★★★ 对哪个项目印象比较深刻深刻,遇到最难的项目是啥? 【同上】
1.问题描述:1)简单介绍这个项目规模、背景 2)什么情况下遇到什么样的 问题
2.你处理这个问题的过程及结果:1)遇到问题你如何思考;2)你如何执行的;
3)处理结果如何
3.通过处理这个问题,你学到了什么或者说通过这个问题,你看到了你们什么 不足,后续动作(采用什么样的方式,在以后的项目中避免再出现这类问题)
1.(使用缓存处理)
在做 Vue 开发移动端 APP 时,有个页面比较常见,左边是对所有菜谱品类的展示,右边 是对对应菜谱的展示,一开始在开发的时候没注意,就直接在 mounted()前面使用 async, 里面使用 await 调了两边接口后,又通过 watch 监听了品类索引变化,调了一遍接口。后面 发现每次切换品类时,页面都有一闪而过的感觉,发现每次都调了一遍接口,这对性能消耗 挺大。所以就尝试的走了 Vuex 做缓存处理。当时解决这个缓存问题用了一些巧妙的方法,首 先缓存的数据,采用的是对象形式,不是数组。这样写起来更快,因为用品类的下标直接做 缓存数据的 key 值,非常好写。不过后面又有点坑,就是我监听的是引用数据类型,不管是 vue 还是 react,引用数据类型发生变化时,页面可能不会更新。后面又在 mutation 中对 uex 中的数据更新时,做了一下深复制,就做好了缓存处理。因为我是根据判断这个对象中 有没有数据去调接口的,如果存在,就不调接口。现在做了缓存没错,那如果以后后台的数 据发生了变化的话,那我这里也不调接口了,后台数据就没有在页面上实现更新,所以在跳
出这个页面的时候还要清下缓存。清缓存要在生命周期结束的时候清,如果碰到了动态组件 把 APP 页面下的 Tap 栏包住的时候, Keep-alive。就不能用 destroyed 生命周期清除, 要用 deactivated 生命周期去清除。这样才有始有终,完成缓存处理。
2.(解决关键词高亮问题---->原理和字符串敏感词替换一样,但是用在关键词高亮上算是 一个技术亮点吧)
用户配置一堆关键词,在页面上将这些关键词高亮,也许你会觉得这有什么难度?用正 则匹配一下出来高亮不就行了吗?但是,一开始,用户的词不多,我确实使用的是遍历,时 间复杂度为 n2。后来用户会配置 100w 量级的词,使用遍历就会使页面卡死崩溃。解决的方 法就是:优化性能,高亮分三步,生成字典树,遍历页面文字,取出文字进行匹配。使用字 典树代替遍历,整个页面 100w 量级的词绘制可以实现在 1 秒以内。3.(封装自定义组件) 在一个小程序项目需求中,要求页面头部 tab 栏切换的同时,对应 tab 栏品类的页面也 要展示出来。你可能会觉得这个需求用个 taroUI 组件库中的 tabs 标签页组件不就可以完成 吗?但是这个需求想满足用户的沉浸式体验,切换页面时需要有独特丝滑的专场特效。所以 当时面临的问题就是,使用的 UI 库的组件默认样式生硬,满足不了需求。我当时是对小程序 原生 swiper 组件进行了二次封装,主要实现了几点自定义需求:头部 Tab 栏品类样式使用 flex 动态布局,实现品类数量可变;使用 slot 插槽来动态渲染 Tab 区块中的内容,配合 原生 swiper 组件使用定义插槽;小程序原生组件<swiper>是有默认高度的,必须手动设置 其高度,这里使用 wx.getSystemInfo 来动态获取屏幕尺寸。自己封装组件,踩了不少坑, 但从中我学习到了:使用小程序的原生组件,并修改其默认的样式;学会使用 slot 插槽, 实现组件内容的差异化;学会了使用小程序原生 api 获取手机信息,用 js 改变组件样式等 等
4.(遇到了难用的轮子)
在写 XXX 小程序项目中需要实现音频播放的功能,官方已经推荐使用新的 API 了,然而 这个小程序官方文档文档写得并不好,很多时候我们会遇到一些需求,或者改变而这些需求 文档里又写得非常模糊,这就比较头疼了。小程序官方文档更新十分频繁,坑非常多。所以 很多时候,我就要去不断地从文档的字里行间猜测,并结合源码一步一步地去跟踪,去尝试 解决这个音频播放问题。但有时候确实超出了我的能力范围,那么我就会把我的问题提炼成 小 demo,到知乎、segmentfault 思否去问,或者提问一些同样用这个轮子的作者,最 终找到了新 API 的使用规范。
注意:这个时候你就要说你最擅长的,一定是你最擅长的点,告诉他这个问题 怎么解决,一定是你最懂的,而且经得起推敲的解决方案。你要准备的不仅仅 是你的项目中有哪些难点,更重要的是和这个难点相关的知识都要准备充分。 所以,你的答案并不是这个项目中最难的点,而是一个最能让你回答好整套相 关问题的难点。
四、前端扮演的角色 ★★★
★★★ 项目研发流程中作为前端开发一般扮演的啥角色?
前端开发一般扮演着一个“团队核心废物”的角色。为什么这么说,首先在项目的研发中, UI 小姐姐总感觉前端开发的页面满足不了她们的设计理念,说你没品味;后端小哥哥觉得前 端开发就像只会写写样式的 js 交互工程师,像极了一个破美工的;测试小哥哥拿着测试报告 说:这锅谁他娘的来背一下。还记得当年那个请你根据手机壳的颜色,来实现 APP 启动的颜 色的产品经理嘛?这些对前端开发的误会难道不能折射出前端是团队里最应该学会沟通的人 嘛?界面有问题需要和 UI 沟通,数据有问题需要和后台沟通,功能有问题需要和产品沟通,测 试的时候给你提 bug 你还需要和测试沟通……毕竟前端是最接近用户的人,用户对一个网站,软 件最直观的感受是反映到前端;交互体验更是前端项目的核心点。 和 UI 的沟通,在工作中我们不应该是被动的实现 UI 的设计,而是应该合理化的提出自己 的想法,不然日后返工浪费的是双方的时间。比如通用组件的设计,每次页面的提示弹窗设计, 再比如你需要做一个图表,用到了 echarts,你完全可以让 UI 基于 echarts 去设计样式,而不 是让她在那里自由发挥,因为你永远不知道设计师的脑子里装了多少创意,这样节省的是两个 人的时间,不会出现他做好样式而你实现不了的尴尬。 和后端联调接口前,先要对业务需求了解透彻,需要哪些数据,有时候明明后台来处理 某个事件很简单,后台非要你来做,这就需要我们对一个需求,一个任务的要有清晰认识了,如 果对任务含糊不清,自己都没搞明白,你只能受后台摆布了.最后可能也会因为任务没有完成 而备受责难了。有理有据,后台开发人员是不会说什么的,否则,后台会很不耐烦的,甚至骂你 的可能都有,本身做后台比较难,尤其在查询数据,取数据,封装数据方面都比较难处理。 面对产品经理的需求,前端应该深刻理解需求,毕竟工作性质影响了一个人的思维逻辑, 前端能站在一个产品经理的角度去思考每一个需求,便显得尤其重要。不放过每一个细节也 很重要。产品经理在设计一个产品的时候,都是从大方向去想问题的,大方向没有错就行了, 细节脱离不了大方向。这是他们想的。但是对于程序来说,却万万不能。因为一个细节的逻 辑往往决定了整个大方向。 举个例子:有一个需求,用户的作品需要提交审核,经过审核才可以让所有人看到。当 产品经理交这个需求给你的时候,你能察觉到什么问题了吗?这里面有几个细节:
1.用户提 交审核后,用户可以不可以再编辑作品;
2.作品是否会多次审核;
3.需不需要记录审核历史;
4.用户作品是否需要有版本的控制,如要产生版本,版本又是如何产生的;
5.审核通过后,
用户可以不可以再修改作品,若不可以,那么是不是其他人就看不见用户作品等等。
我认为前端开发是团队里最应该学会沟通的人,一个好的前端开发模式可以推动整个项 目的进步的,尽管有时可能会被误解成废物,但是这何尝不是大家公认的核心呢?
五、项目有啥优化 ★★★
★★★ 现在有的项目中觉得哪些项目可以继续优化,为啥没有优化?
之前用 vue 做了一个动态官网项目,后期客户要求 seo,百度上之前搜索不到官网地址, 后来在项目的入口文件 index.html 页面加上了,固定的 meta 标签,加上 name 名为 keywords、 description 的 meta 标签。以上做了个简单的 seo 优化,这个项目有几个官网,但是其中 只有一个官网要求 seo,也就是在百度能够搜索到,当时为了应急,就写死了,但是,其它 的网站也就会受到干扰了,也就是对于一个项目对应几个官网,写死的 meta 标签做 seo 是 不科学的。
如果这个项目要解决 seo 优化,可以用服务端渲染(ssr),如果项目刚开始就考虑到 seo,采用服务端渲染,那么就用服务端渲染就得了。但是一般来讲,项目做到后期才会考虑 到 seo 的问题,这时再去搞服务端渲染,相当于重头写项目,非常耗费人力物力。所以先只考虑在首页加入 meta 标签提供一些元数据,使用简单、具有表意性的 title 以及使用 h5 提供的具有语义化的标签(不要一堆 div),生成对 search engine 友好的 sitemap,使用合理的 html 结构(比如按标题、内容、页脚这样的顺序、或者将重要的内 容放在 html 前,其他放在后)
六、总结过项目吗?★★★
★★★ 平时写项目总结么,一般总结哪些东西?
平时在写项目的时候,会写项目总结,常常会遇到什么技术难点后,先用自己积累的知 识点去尝试解决,如果遇到不会的,我就会在网上查看文档,通过翻阅资料解决问题。在解 决问题后,一般我会将我认为有坑的地方记录下来。 比如,最近我做的一个比较有特点的项目,用的是 React + taro + koa 框架,完成类 似听书小程序。里面有个书城页面,是自己封装了品类筛选的组件。用的是小程序 scroll-view 的原生 API,这里面有好多个坑,首先他有一个 API,是 scrollintoView, 这个 API 的值不能数字开头,但是后端给的数字一般都是 id,数字嘛。这只能自己把后端传 的数字处理成 string 类型。最后还有一个样式的坑,你一定要按照官方文档中给的 CSS 样 式来,给 scroll-wrap 加上 white-space:nowrap 和宽度百分百,才能实现滚动的效果。 除了总结遇到的问题,还会总结一下自己负责模块的一些规范,比如打包技术,图片的 使用,自己使用了那些 UI 库的组件实现了什么具体的功能。自己负责的模块中联调了哪些接 口。最后总结下大概完成了哪些需求。
七、持续学习么?★★★
★★★ 工作中能够持续学习么?
工作中当然可以持续学习,我认为每次对自己的总结就是很好学习机会,可以是工作上 的总结,生活上的总结,某一件小事的总结都可以学习。 总结自己掌握的前端知识体系,总结知识体系的过程是一个查缺补漏的过程。遇到没掌 握或者了解不深的知识点,务必去了解、搞清楚,否则就不算掌握。还可以,总结自己做过 的项目中有哪些难点,或者技术架构。涉及到的所有技术点都可以挖一下,看看有没有某个 点是自己描述不清的。
有空闲时间,会去 leetcode 社区上找点算法题,可以去 bestofjs 社区看看社区又出 了什么比较前沿的技术,框架 。还可以去 Git 上看看别人写的代码,或者翻翻 Vue,React 源码研究研究。
八、学习动力 ★★★
★★★ 学习的动力怎么来的,如何维持?
我对前端开发学习动力来自对解决问题的成就感,这一个过程,是让人享受的。比如刚 步入前端的时候,当我刚学会怎么使用 css 属性,去给静态页面添加旋转,缩放,背景颜色 渐变的时候,那时候满脑子都是花里花哨的效果,在练习的 demo 中,一些地方本来朴实无华, 但我偏偏想用用动画,渐变去玩一玩。后面学到用 js 操作 dom 元素,自己玩玩计时器,页面 上能玩的更花里胡哨了,就感觉非常舒服。在又学会了 jq,ajax 配合表单的使用,向后端传 递数据时,感觉就非常到位。慢慢就觉得前端开发非常有成就感。现在前端开发,知识体系 庞大,各种框架组件,组件写法百花齐放,这难道不是一种让人兴奋的事嘛?我在工作中不 但可以做着让人兴奋的事,还可以拿工资,这难道不舒服嘛?
写在后面
其实对于前端面试来说,首要就是要有面试,简历不行就改简历,项目不行就找办法,不是完全 没有办法,如果实在不想自己耗费精力也可以call我,会尽力给予帮助的,祝大家都能找到理想的工作,加油~