五月前端面试报告 | 上海
create by db on 2020-5-14 22:37:37
Recently revised in 2020-6-8 22:29:17
前言
后浪,你摆摊了吗?
时至6月,新冠影响渐小。
虽然今年注定是全世界的经济寒冬,但地摊还是要摆的,面试也是也要去的。
先说下本人的情况:坐标上海,三非本科(非双一流非计算机专业),前端老菜鸟,小公司在职,技术栈Vue + ElementUI。本来打算年后跳槽的,被疫情逼到了年中。五一开始做面试准备,主要投递渠道是Boss, 历经近一个月时间,先后面试了有七家(不包括电话面试),拿到三家offer。在此向大家做一次面试报告,也是自己的阶段总结。
正文
先写面试经历及面试问题,后附自己的一些答案。请按需查阅。
公司A
公司情况:
大厂
只能说我胆子比较肥——刚开始就撞到了新BAT头上。这个是猎头推荐的。做了一些准备,果不其然还是栽了。一面是视频面面试,面试官是非常nice的,会根据个人简历去提一些问题,基础知识较多,要手写代码!要手写代码!要手写代码!
问题:
-
三栏布局的实现及优缺点
-
文字单行显示/三行显示
-
重绘和回流
-
手写斐波那契数列及其优化
-
查看代码输出,什么是宏任务和微任务,都包括哪些?
-
编写javascript深度克隆函数deepClone
-
Vue路由的两种模式,介绍其原理和优缺点
-
编写js事件绑定函数
const Event = {
on() {} // 绑定
off() {} // 解绑
trigger() {} // 触发事件
};
- 手写去重函数
const arr = [1, '1', '1', 'NaN',NaN,'NaN', {a: 1}, '{a: 1}', {a: 1}]
- Vue里面 mixin/自定义指令/v-if/ diff算法
结果:
挂了
收获:
由于准备不足(我菜我不说),加上有一些知识平时没有认真做储备,磕磕巴巴的答完了大部分问题,异步/mixin/diff之类没深入了解过,好在面试官很nice,会一步一步引导你思考——然而还是挂了。
得到的教训就是:不能光满足于做一个coder(CV工程师?),知其然也要知其所以然,基础很重要,理解很重要,最重要的还是能把你想说话的清晰的表达出来。
公司B
公司情况:
外包公司的一个业务部门,做的是自己项目,需要中高级前端配合后台实现(本身无前端)
一面:
由于本部门没有前端,他们从其他部门借了一个前端leader(估计高级)来做面试官。可能因为对他们项目不是特别了解,着重考察基础。
问题:
-
HTML语义化
-
CSS3新特性
-
重绘和回流
-
闭包及其应用
-
ES6新特性,追问了let、promise、class 等
-
简述webpack配置项
-
你所知道的排序算法,及其实现方式
-
Vue组件传参的几种方式
……还有很多关于js对象的一些API之类
二面:
一面完了就是直接进的二面,二面面试官是本部门的架构师(很有范),主要聊得是项目和一些问题解决方案。
-
为什么跳槽
-
基于项目需求,如何需求调研,选择合适的框架及方案,详述过程
-
做技术为什么考PMP(我简历上有写,比较关心能不能踏实做技术)
-
工作中遇到最困难的问题是什么
-
有没有带过团队
-
以后的职业规划
HR面:
然后就进入HR面,HR是个身材很棒的小姐姐(带着口罩没看到脸)
-
什么时候能入职
-
期望薪资多少
……口水话
结果:
拿到了offer,但是薪资没达到期望值,拒了
收获:
很有收获的的一次面试经历,增加了见识,也给了我一定的信心。面试毕竟是一个双向选择的过程,能遇到一些值得学习的人,思考一些平时没想过的问题,也是一次不错经历。
公司C
公司情况:
小公司,做自己项目,有两个前端(都很年青),估计要招个前端leader,但是JD并没有写
面试:
公司十几个人的规模,是总经理在boss上发的面试邀请,离我住的地方颇近,所以还是很感兴趣的。但是不知道是领导不在还是其他原因,派出两个小朋友做面试官。
这段面试经历并不是很好。两位面试官他们估计没什么经验,也没有准备好需要问的问题。问的一些话语焉不详,还有就是拿工作中的一些问题来提问构思……
结果:
也许相互都不是特别满意,没下文了
收获:
很糟糕的一次面试经历。
公司D
公司情况:
中型公司,做政府项目
一面:
同样不是特别愉快的一次面试经历。
面试定的是下午两点,我提前十分钟到的。然而同一块来的有1个前端,3个测试,6个后台(压力颇大)——他们的HR把所以有人订在了同一时间?!然后前台让大家排排队领个人信息表,现场打印面试题……一波操作20分钟过去了,然后就是半个小时做题,做完了等着被面试。。。
等到接近四点我才被通知可以面试——来都来了,就面一下咯——出来面试,心态要好。然后最骚的操作来了,我被HR带到一间小办公室,里面只有一台电脑——面试官在远程面试。当时心里一万匹草泥马跑过……但是,来都来了……
问题:
-
做下自我介绍
-
用户登录流程及权限判定,用户信息存储
-
路由跳转,页面如何刷新
-
介绍下平时工作内容及流程
-
介绍个人工作经历
-
发了一个闭包的题看输出
-
会不会React
-
有什么想问我的
面完第一件事告诉HR——如果有二面,而且还需要远程的话,烦请提前电话告知(我真有礼貌(⊙o⊙)…)
二面:
二面是晚上下班在家视频面试的(微信群聊)
定的8点,面试官迟到十分钟。HR跟我说是老总面试,我以为要聊项目,吹牛B谈理想(一面基本都没怎么问),结果碰到了一个很接地气的老总。
问题:
-
说说盒模型类型及区别
-
div垂直居中
-
怎样写一个可拖曳的div,怎样将他拖到其他节点内
-
Vue生命周期
-
Vue路由守卫
-
Vue组件传参
-
现场画一个三行三列自适应布局
结果:
拿到了offer,但是由于对该公司的观感和上班距离原因,拒了
收获:
很奇葩的一次面试经历,长见识的那种。
公司E
公司情况:
中大型公司(听过名字那种),做内部项目,JD要求资深
面试:
很舒适的一次面试(可能我是自虐狂)。
HR是个大帅哥(很少见男性又很帅的HR),公司很多人,有些嘈杂。面试直接是在门口待客小桌子上进行的。面试官居然老乡,很厉害,问的非常详细,由浅入深——基本上对所有前端知识做了一个梳理。
问题:
-
HTML语义化
-
用过的一些HTML5标签
- 和 import的作用及区别
-
盒模型分类和区别
-
绝对定位和相对定位
-
BFC定义/作用/触发条件
-
display的属性
-
选择器优先级
-
三栏布局
-
ES6语法:promise/箭头函数/class
-
闭包的用法和作用域
-
原型链,实现继承的方法
-
异步及其解决方案,宏任务和微任务及其流程
-
跨域
-
实现深拷贝
-
实现promise
-
http的GET和POST区别/状态码
-
http的GET和POST
-
Vue生命周期/组件通信/响应式实现/路由模式/路由守卫
-
webpack的打包原理、常用的loader和plugin,以及一些常用配置
-
node.js的异步操作
-
TypeScript的认识
-
前端微服务的实现方法
-
有没有带过团队
-
你最擅长什么领域
前面回答基本没问题,但到后面webpack、node、微服务那一块,就有些捉襟见肘了。不过面试官很有耐心,每个回答都是记录,不清楚的也很耐心的解释。经过沟通发现,他这几天面了很多人了。。。
一面面试官对我的评价不错(也许是老乡加成),然而被很遗憾的通知二面面试官没时间。。。
结果:
挂了
收获:
很有收获的一次面试,面试官给了很多指导性意见及建议,自己对资深有了更切身的认识,也明确了进一步学习的方向。
公司F
公司情况:
中小型文创公司
面试:
面试官: 接受996吗?
我:请问贵公司招聘预算多少?
结果:
这是我面试时间最短的一次面试。
收获:
很感谢面试官的单刀直入,避免了浪费大家时间。
个人可以接受加班的,赶项目的话义务加班也可以,但我真不想进ICU。
公司G(最终入职)
公司情况:
创业公司
电话面试:
面试官应该是看着我博客来面的我,一开始问的是一些基础知识,后来就问项目。问题就不一一列举了,跟之前列的大都重复,毕竟前端知识虽然比较杂,主要知识点还是可以抓住脉络的。
一面:
现场一面也是没有太多的问题,小姐姐很随和,没问过多关于技术的问题,因为之前电话都聊过了,主要聊得一些就是怎么入行,平时工作遇到的问题,解决方案,平时下班都做什么,个人发展规划,写博客什么感受,最近在学什么,对加班的看法……诸如此类
二面:
二面是应该是技术总监,主要问的就是关于平时的学习(我自己介绍有说这些),平时的一些学习路径、个人发展规划及期望。
三面:
三面是公司CEO和HR一块面的,主要问的就是关于项目的问题,个人负责的的模块,关于一些项目选型的问题,还有一些项目上线的流程,临场问题的解决方案,为什么想跳槽,对公司的期待,还有一些公司的介绍。
结果:
隔天拿到了offer,蛮喜欢公司氛围的,大家都比较随和。比较期待入职。
收获:
待入职公司也是希望找一个能干活的前端。希望首先将分内工作做好,多接触些其他的业务(类似多端、小程序、app之类),踏踏实实积累沉淀,提升技术,熟悉业务,深入行业,争取做一个斜杠青年。
总结
以上即是本次面试历程的一些总结了,有详有略,应为有的面试我有录音做复盘,有的不方便或忘记录了,就全靠记忆,可能有的地方有些遗漏,见谅哈。
通过这几场面试下来,感觉今年的就业压力其实蛮大的。当然,是金子总会发光,人才在哪里都不愁找工作——所以说小伙伴们加油啊——不要怂,盘它!
个人现在的定级在中级+左右,在上海来说,大厂的薪资相对会高一些,不过对基础及算法的要求也高一些;小公司的话,对算法的要求不高,浏览器原理和JS、ES占的比例较大,框架其次,最好还要有些项目打包经验。
写这篇博客呢,主要是自己水一篇博客做个阶段总结,如果能帮助到大家是最好了。
建议
最后对小伙伴们提些建议:
-
平时的积累很重要:工作中遇到的一些问题及其解决方式,我们可以记录下来,抽空做个总结。最好就是找个平台写博客,掘金、GitHub、博客园、CSDN都可以,好记性不如烂笔头,自己写一遍比看一遍好使的多。在线博客不进方便自己查阅,面试玩意碰到记不太清的知识点还能说——我博客上有总结过。
-
简历不要给自己挖坑:会啥就写啥,写啥就会啥。正常的面试官都会根据简历来提问,所以简历上不要出现自己不懂的名词——不懂就去查,去背,哪怕不特别理解到时候也能说个一二三来。不然一问三不知真的尴尬。
-
面试之前要做准备:面试就是考试,考试我们就得复习。前端的知识体系还是很明朗的——页面、样式、JS、框架、项目打包及构建,先掌握自己拿手的,然后扫除盲点。
-
别在一个坑掉进去两次:和面试官切磋,为了了解目前的就业形势。了解并正视自己的不足;当这个面试有些问题你答不上来时,没关系,回去查资料,看视频,做复盘,一定要记住它,下次你就可以游刃有余了。怕忘的话可以录音。
-
不要裸辞!不要裸辞!不要裸辞!:重要事情说三遍,如果有房贷车贷的话,裸辞找工作压力真的很大——手里有粮,心里不慌。当然,土豪随意……
-
尽量不要把时间线拖太久:一边上班一般找工作是蛮辛苦的,要想请假理由,下班要准备面试。所以要一鼓作气,尽量突击半个月多拿几家offer,时间线拉太长可能会懈怠(我就是拖得有些久了)。尽量有选择则的、找匹配(薪资、能力、通勤之类)的公司去面试,决不能接到面试邀请就去,不然只是浪费自己的时间。
-
端正心态,坚持学习:技术日新月异,框架层出不穷。既然选择了这个行业,就要端正心态,努力学习,提升技术,熟悉业务,深入行业,别让后浪拍死。
附录
参考文档
1. 三栏布局的实现及优缺点
布局方案 | 实现 | 优点 | 缺点 |
---|---|---|---|
Float布局 | 左右中三列,左列左浮动,右列右浮动,中间列设置左右margin | 比较简单,兼容性也比较好 | 浮动元素脱离文档流,使用的时候只需要注意一定要清除浮动。 |
Position布局 | 左中右三列(无顺序),根据定位属性去直接设置各个子元素位置 | 快捷,设置很方便 | 元素脱离了文档流,后代元素也脱离了文档流,高度未知的时候,会有问题,有效性和可使用性比较差 |
Table布局 | 左中右三列,父元素display: table;子元素display: table-cell;居中子元素不设宽度 | 使用起来方便,兼容性也不存在问题 | ①无法设置栏边距;②对seo不友好;③当其中一个单元格高度超出的时候,两侧的单元格也是会跟着一起变高的 |
Flex布局 | 左中右三列,父元素display: flex;两侧元素设宽;居中子元素flex: 1; | 比较完美 | 存在IE上兼容性问题,只能支持到IE9以上 |
Grid布局 | 左中右三列,父元素display: grid;利用网格实现 | 最强大和最简单 | 兼容性不好,IE10+上支持,而且也仅支持部分属性 |
2. 文字单行显示/三行显示
单行文本溢出隐藏变为...
p {
/* 隐藏元素溢出内容 */
overflow: hidden;
/* 单行显示 */
white-space: nowrap;
/* 溢出显示省略号 */
text-overflow: ellipsis;
}
多行文本溢出隐藏变为...
p {
overflow: hidden;
/* 将对象作为弹性伸缩盒子模型显示 。 */
display: -webkit-box;
/* 限制在一个块元素显示的文本的行数,即行数设置 */
-webkit-line-clamp: 3;
/* 规定框从上向下垂直排列子元素 */
-webkit-box-orient: vertical;
}
3. 重绘和回流
回流:当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(其实我觉得叫重新布局更简单明了些)。每个页面至少需要一次回流,就是在页面第一次加载的时候。
重绘:当render tree中的一些元素需要更新属性,这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
区别
-
回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流
-
当页面布局和几何属性改变时就需要回流 比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变
-
回流往往伴随着布局的变化,代价较大:
-
重绘只是样式的变化,结构不会变化:
4. 手写斐波那契数列及其优化
什么是斐波那契数列: 斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=1,F(1)=1, F(n)=F(n-1)+F(n-2)(n>2,n∈N*), 这个数列从第3项开始,每一项都等于前两项之和
function Fibonacci (n) {
if ( n <= 1 ) {return 1};
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
这个方法算是代码最少也容易理解,但是当n较大时很快产生栈溢出,引发原因是“调用帧”过多,出现浏览器假死现象。详情参阅函数扩展之尾调用优化——阮一峰。
- 递归(优化版)
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
if( n <= 1 ) {return ac2};
return Fibonacci2 (n - 1, ac2, ac1 + ac2);
}
此方式是函数尾调用优化之后的写法(默认参数ES6及以后版本支持,ES5请使用常规默认值写法),理解上稍微复杂,但是不会发生栈溢出,推荐使用。
- 普通循环版
function Fibonacci3(n) {
if (n===1 || n===2) {
return 1;
}
var n1 = 1, n2 = 1, sum;
for (let i = 2; i < n; i++) {
sum = n1 + n2
n1 = n2
n2 = sum
}
return sum
}
循环版本最好理解,就是给初始值,然后不断的累加即可
- 解构赋值版
var Fibonacci4 = function (n) {
if (n===1 || n===2) {
return 1;
}
let n1 = 1; n2 = 1;
for (let i = 2; i < n; i++) {
[n1, n2] = [n2, n1 + n2]
}
return n2
}
循环版本最好理解,就是给初始值,然后不断的累加即可(用了解构赋值,代码更简洁)。
5. 查看代码输出,什么是宏任务和微任务,都包括哪些?
setTimeout(function() {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
输出:
2
3
5
4
1
宏任务
# | 浏览器 | Node |
---|---|---|
setTimeout | √ | √ |
setInterval | √ | √ |
setImmediate | x | √ |
requestAnimationFrame | √ | x |
微任务
# | 浏览器 | Node |
---|---|---|
process.nextTick | x | √ |
MutationObserver | √ | x |
Promise.then catchfinally Async/Await | √ | √ |
执行机制:
- 先执行主线程
- 遇到宏队列(macrotask)放到宏队列(macrotask)
- 遇到微队列(microtask)放到微队列(microtask)
- 主线程执行完毕
- 执行微队列(microtask),微队列(microtask)执行完毕
- 执行一次宏队列(macrotask)中的一个任务,执行完毕
- 执行微队列(microtask),执行完毕
- 依次循环。。。
6. 编写javascript深度克隆函数deepClone
// 深拷贝
/**
* 深拷贝对象,可以正确序列化日期
* @param {*} obj
*/
export const DEEP_CLONE = function (obj) {
let objClone = Array.isArray(obj) ? [] : {}
if (obj && typeof obj === 'object') {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 判断ojb子元素是否为对象,如果是,递归复制
if (obj[key] && typeof obj[key] === 'object') {
// 深拷贝日期类型
if (obj[key] instanceof Date) {
objClone[key] = new Date(obj[key].valueOf())
// console.log('deepClone', objClone[key])
} else {
objClone[key] = DEEP_CLONE(obj[key])
}
} else {
// 如果不是,简单复制
objClone[key] = obj[key]
}
}
}
}
return objClone
}
7. Vue路由的两种模式
hash
原理
- 早期的前端路由的实现就是基于location.hash来实现的,location.hash的值就是URL中#后面的内容 其实现原理就是监听#后面的内容来发起Ajax请求来进行局部更新,而不需要刷新整个页面。
- 使用hashchange事件来监听 URL 的变化,以下这几种情况改变 URL 都会触发 hashchange 事件:浏览器前进后退改变 URL、a标签改变 URL、window.location改变URL。
优点
兼容低版本浏览器,Angular1.x和Vue默认使用的就是hash路由 只有#符号之前的内容才会包含在请求中被发送到后端,也就是说就算后端没有对路由全覆盖,但是不会返回404错误 hash值的改变,都会在浏览器的访问历史中增加一个记录,所以可以通过浏览器的回退、前进按钮控制hash的切换 会覆盖锚点定位元素的功能
缺点
不太美观,#后面传输的数据复杂的话会出现问题
history
原理
- history 提供了 pushState 和 replaceState 两个方法来记录路由状态,这两个方法改变 URL 不会引起页面刷新
- history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或a标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和a标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
- pushState(state, title, url) 和 replaceState(state, title, url)都可以接受三个相同的参数。
优点
使用简单,比较美观
pushState()设置新的URL可以是任意与当前URL同源的URL,而hash只能改变#后面的内容,因此只能设置与当前URL同文档的URL
pushState()设置的URL与当前URL一模一样时也会被添加到历史记录栈中,而hash#后面的内容必须被修改才会被添加到新的记录栈中
pushState()可以通过stateObject参数添加任意类型的数据到记录中,而hash只能添加短字符串 pushState()可额外设置title属性供后续使用
缺点
前端的URL必须和向发送请求后端URL保持一致,否则会报404错误
由于History API的缘故,低版本浏览器有兼容行问题
两种不同使用场景
- 从上文可见,hash模式下url会带有#,当你希望url更优雅时,可以使用history模式。
- 当使用history模式时,需要注意在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
- 当需要兼容低版本的浏览器时,建议使用hash模式。
- 当需要添加任意类型数据到记录时,可以使用history模式。
8. 编写js事件绑定函数
const Event = {
on() {} // 绑定
off() {} // 解绑
trigger() {} // 触发事件
};
class Event {
constructor() {
// 为了查找迅速使用了对象
this._cache = {};
}
// 绑定事件
on(eventName, callback) {
/* 为了查找方便和节省空间, 把同一类型事件放到数组中
* 因为数组是有序的, 逻辑上是队列, 先绑定先触发
* */
// 如果有就放入, 没有就新建, 然后再看下是否有放入函数,没有就加入
let fns = (this._cache[eventName] = this._cache[eventName] || []);
// 如果事件方法没有的话就放入到字典进去
if (fns.indexOf(callback === -1)) {
fns.push(callback);
}
return this;
}
// 触发事件
trigger(eventName, data) {
// 看下字典里有没有这个函数名字, 有的话就触发它
let fns = this._cache[eventName];
if (Array.isArray(fns)) {
// 有的话就对立面的每一个function传入参数data
fns.forEach(fn => {
fn(data);
});
}
return this;
}
/*解绑, 看下字典里如果有这个事件名字就去
* 看下要删除什么
* */
off(eventName, callback) {
let fns = this._cache[eventName];
if (Array.isArray(fns)) {
if (callback) {
let index = fns.indexOf(callback);
if (index !== -1) {
fns.splice(index, 1);
}
} else {
// 全部清空
fns.length = 0;
}
}
return this;
}
}
const event = new Event();
event.on("test", a => {
console.log(a);
});
event.trigger("thet", "hello world"); // 绑定后就输出
event.off("test");
event.trigger("test", "hello world"); // 解绑后就不显示了
9. 手写去重函数
const arr = [1, '1', '1', 'NaN',NaN,'NaN', {a: 1}, '{a: 1}', {a: 1}]
// 利用for嵌套for,然后splice去重(ES5中最常用)
function unique2(arr) {
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) { //第一个等同于第二个,splice方法删除第二个
arr.splice(j, 1);
j--;
}
}
}
return arr;
}
// 利用hasOwnProperty
function unique7(arr) {
var obj = {};
return arr.filter(function (item, index, arr) {
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
// 利用filter
function unique4(arr) {
return arr.filter(function (item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
10. mixin / 自定义指令/ v-if/ v-ssd/ diff算法
11 手写ajax
// 手写ajax
function get(){
var req = new XMLHTTPRequest();
if(req){
req.open("GET", "http://test.com/?keywords=手机", true);
req.onreadystatechange = function(){
if(req.readyState == 4){
if(req.status == 200){
alert("success");
}else{
alert("error");
}
}
}
req.send();
}
}
12 事件绑定函数+事件委托
function delegate(element, eeventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
})
}
13 Promise实例
// Promise
function fn(){
var promise = new Promise(function(resolve,reject){
// ... some code
if(/*异步操作成功*/) {
resolve(value) // 成功调用resolve 往下传递参数 且只接受一个参数
}else {
reject(error) // 失败调用reject 往下传递参数 且只接受一个参数
}
});
return promise
}
fn.then(function (r) {
console.log('成功: ' + r);
}).catch(function (reason) {
console.log('失败: ' + reason);
});
// 全部成功调用
Promise.all([promise1,promise2]).then(sucess1,fail1)
// 有一个成功就调用
Promise.race([promise1,promise2]).then(sucess1,fail1)
14 自己实现Promise
class MyPromise{
constructor(executor) {
this.status = "pending"; // 初始化状态为pending
this.value = undefined; // 初始化返回的成功的结果或者失败的原因
// 这里是resolve方法,成功后执行,将状态改变为resolved,并且将结果返回
let resolve = result => {
if(this.status !== "pending") return; // 状态一旦改变,就不会再变
this.status = "resolved";
this.value = result;
}
// 这里是reject方法,异常时执行,状态改为rejected,并且将失败的原因返回
let reject = reason => {
if(this.status !== "pending") return;
this.status = "rejected";
this.value = reason;
}
// try、catch捕获异常,如果错误,执行reject方法
try {
executor(resolve, reject)
} catch(err) {
reject(err)
}
}
}
15 VueX的原理和使用
16 Vue权限路由实现方式
17 js判断对象和数组
18 js 中的new()到底做了什么?
- [完全搞懂js 中的new()到底做了什么?](https://www.jianshu.com/p/bf4cda6b515f)
19 排序
进阶
20 Vue路由传参--------params和query的区别
背景:项目中需要跨页面传值,如试题id,遇到了刷新后,传的值消失,所以研究了以下两者的区别
- params只能用name来引入路由,query用path来引入
- params类似于post,query更加类似于我们ajax中get传参,说的再简单一点,前者在浏览器地址栏中不显示参数,后者显示,所以params传值相对安全一些。
- 取值用法类似分别是this.route.query.name。
- params传值一刷新就没了,query传值刷新还存在
this.$router.push({
path:"/detail",
params:{
name:'nameValue',
code:10011
}
});
this.$router.push({
path:'/xxx'
query:{
id:id
}
})
总结:少量参数可以用此方法,如果有大量公共数据,可以采用Vuex或本地存储的方式。
后记:Hello 小伙伴们,如果觉得本文还不错,记得点个赞或者给个 star,你们的赞和 star 是我编写更多更丰富文章的动力!GitHub 地址
文档协议
db 的文档库 由 db 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于github.com/danygitgit上的作品创作。
本许可协议授权之外的使用权限可以从 creativecommons.org/licenses/by… 处获得。