前言
6.29 上午面一家深圳健康160,下午考试+面杭州端点+纬创 以下是杭州端点的面试题(面了43分钟, 前面拉胯,后面稍微好点),及其自我总结:
1. 自我介绍+项目介绍
2. Vue双向数据绑定原理
我的回答:
采用“数据劫持”结合发布者-订阅者模式,通过Object.definedProperty()的setter和getter来劫持data的各个属性,当数据变化时,通知订阅者,来触发相应的监听回调。
3. Vue监听数组
我的回答:
我说好像不能监听数组,但是我记得可以深度监听(deep:true) 但是我没说...
查资料也有说重写数组方法...
4. Vuex
我的回答:
Vuex是Vue的状态管理模式,相当于一个共享仓库,其他页面可以访问这个仓库;Vuex里面有五个属性:
-
State,存储数据。
-
Getters:获取数据,相当于计算属性( computed )。
-
Mutations:唯一能修改store状态的方式,是同步的。
-
Actions:提交Mutations修改的数据,是异步的。
-
Module:当一个store文件太大了,可以拆分成多个模块,组合在一起。
总结的回答:
1. Vuex是Vue的状态管理模式,相当于一个共享仓库,其他页面可以访问这个仓库;
2. Vuex状态存储是响应式的,当Vue组件从store中读取状态时,如果store的状态改变了,那么用到这个store的组件也会更新;
3. State: 存储数据;组件使用 store.state. 获取数据。
4. Getters: 获取数据,相当于state计算属性( computed ),通过this.$store.getters.获取。
5. Mutations: 唯一能修改store状态的方式,只能是同步函数 this.$store.commit(方法名,值)。
6. Actions: 提交Mutations修改的数据,异步操作。
7. Module: 模块化Vuex,当一个store文件太大了,可以拆分成多个模块,让每一个模块都有自己的State、Getters、Mutations、Actions、Module。
5. axios拦截器
我的回答:
只用过响应拦截器,当返回的状态码不是200就进入错误页面。(没细说...)
总结回答:
应该说返回的状态码不同,进入不同的页面(403:无权访问;404:资源不存在;500:服务器内部错误;503:请求太过频繁,稍后再试)。
6. js数据类型 判断引用数据类型
我的回答:
-
基本数据类型:Number、String、Boolean、Null、Undefined、Symbol(ES6新增)、BigInt(ES11新增);
-
引用数据类型:Function、Array、Object、Date、RegExp。 (忘说两者的区别了...)
3.instanceof和Object.prototype.toString.call() 总结的回答:
-
分别说出有哪些
-
基本数据类型存在栈中,引用数据类型存在堆中,其指针存在栈中。
-
typeof:可以判断基本数据类型
-
如何判断引用数据类型:可以用instanceof判断;
也可以用Object.prototype.toString.call()
判断数组:Array.isArray()
7. instanceof 的限制
我的回答: 我回答成了:instanceof判断 null 和 undefined了...(会报错)
总结的回答: instanceof 左边必须是对象
红宝书P142:使用instanceof的问题是假定只有一个全局执行上下文。如果网页里有多个框架,则可能涉及两个不同的执行期上下文,因此就会有两个不同版本的Array构造函数。如果要把数组从一个框架传给另一个框架,则这个数组的构造函数将有别于第二个框架内本地创建的数组。 所以又出现了Array.isArray(),该方法确定一个值是否为数组,不管它是哪个全局执行上下文中创建的。
8. instanceof 原理
我的回答: 访问原型上面是否有该方法。
总结的回答: MDN的描述:instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
9. 实现instanceof
我的回答: new一个实例,把它的__proto__属性指向构造函数的prototype
总结的回答:
10. 原型、原型链
我的回答: 每一个对象都有prototype,如果是继承的话,访问构造函数原型上的方法,如果构造函数的原型上没有该方法,就会想构造函数原型的原型上去找,这样就形成一条链,原型链的顶端是Object。
总结的回答:
原型的概念:每一个javascript对象(除null外)创建的时候,就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。
person. __ proto __ == Person.prototype
Person = Person.prototype.constructor
11. 继承
我的回答: 我说有6种,但是没列举出来,因为每种的优缺点我忘了...
总结的回答:
-
借用构造函数:子类构造函数中使用call()或apply()
-
原型链继承:父类的实例作为子类的原型
-
组合继承:结合前两者的优点
-
原型式继承:利用空对象为中间,将对象赋值给空对象构造函数的原型(浅复制)
-
寄生式继承:使用原型式继承对一个目标对象进行浅复制,增强这个浅复制的能力
-
寄生组合继承:结合借用构造函数传递参数和寄生模式实现继承(最推荐的方法) 后续会单独写篇文章。
12. new实例化对象的过程
我的回答:
- new一个空对象
- 将该对象的__ proto__ 指向构造函数的原型 后面就忘了 (改变this指向)
总结的回答:
-
创建一个空对象 let person = {}
-
将新对象的proto指向构造函数的prototype person.__ proto __ = Person.prototype
-
改变this指向 Person.call(person) //{}.构造函数()
-
将初始化完毕的新对象地址,保存到等号左边的变量中
13. this指向(严格模式)
我的回答:
-
全局上下文
-
函数内部的
-
eval(不推荐)
-
严格模式下:this为undefined 总结的回答:
-
全局上下文中,不管是严格模式还是非严格模式,this都指向window
-
函数上下文,非严格模式:this指向调用函数,非严格模式:this为undefined
-
eval考虑
-
箭头函数的this:离它最近的外层普通函数的this,而且不能改变
-
new关键字调用函数时,this指向实例对象
-
对象调用,指向对象
14. 改变this指向的方法
我的回答:
-
call():传入的参数是一个一个的
-
apply():传入的参数是数组
-
bind():返回一个新的函数,多个bind只有第一次有效
15. {} === {}
我的回答: false,对象是引用类型,存在堆中,每个对象都有自己的空间。
16. 闭包、优缺点
我的回答: 形式上,函数内部返回一个函数,返回的函数对父级作用域的变量存在引用。 优点:私有变量(构造函数的特权方法)、延长变量的作用域 缺点:不释放会引起内存泄漏(占用内存,使我们无法使用)
17. 防抖和节流
我的回答:
防抖:输入框持续输入,设置固定的时间,当这段时间不在输入,就执行该函数。
应用场景:
-
输入框搜索内容,通过防抖来节约流量;
-
不断触发window.resize事件(改变窗口大小),可以使用防抖。
代码实现: 定时器 节流:再规定的时间内,不管触发多少次,只执行最后一次,即单位时间内,只执行一次。
应用场景:鼠标持续点击,单位时间内只执行一次
代码实现:
-
时间戳
-
定时器
18. 箭头函数与普通函数的区别
我的回答:
-
省略function关键字和return;
-
当参数只有一个时,可以省略小括号;多个参数时,必须使用小括号;当代码只有一行时,可以省略花括号;
-
本身没有this,继承当前上下文中,最近的普通函数的this,而且不能改变this指向;
-
不能作为构造函数,不能使用new来是实例化对象,所以没有原型(prototype);
-
没有arguments,可以用rest代替。
19. js延迟加载
我的回答: 回答错了,我以为异步加载就是延迟加载...
script标签可以设置defer和async两个属性,实现延迟加载 defer:异步下载脚本,直到文档解析完成后执行该脚本(有序) async:异步下载脚步,下载完成立即执行,脚步执行完后(不保证执行顺序),页面继续解析。
总结的回答:
延迟加载:
-
使用setTimeout延迟加载;
-
js脚本放在最后面。
异步加载:
-
defer:异步下载脚本,直到文档解析完成后执行该脚本(有序);
-
async:异步下载脚步,下载完成立即执行,脚步执行完后(不保证执行顺序),页面继续解析。
20. document.write和document.innerHTML
我的回答: 面试官说了两三遍,我都没听清楚啥第一个说的是啥,就听到后面的有个docunent.innerHTML,我以为是document.right,我还在想,我都没见过这个。。。 最后我回答了innerHTML和innerText。
总结的回答: 复习一下innerHTML和innerText:
- innerHTML:获取文本信息,包括标签
- innerText:获取文本信息,不包括标签
21. 重排和重绘
我的回答:
重排也叫回流:当DOM节点新增或删除,位置大小发生变化,会引起回流;
重绘:改变元素的颜色,字体和visibility会引起重绘。
嘴瓢了,最后改正了:重排必然会重绘,但重绘不会重排。
22. js哪些操作会引起内存泄漏
我的回答:
-
闭包
-
意外的全局变量(函数内部声明的全局变量)
-
未清空的定时器和计时器
23. 事件流
我的回答: 捕获阶段 -> 事件阶段 -> 冒泡阶段, 举了个例子。
总结的回答:
DOM2级,addEventListener事件监听,有事件冒泡;
捕获阶段 -> 事件阶段 -> 冒泡阶段
捕获阶段: Window -> Document -> < html> -> < body>...< div> -> < span> 冒泡阶段: < span> -> < div>...< body> -> < html> -> Document -> Window
例子:若点击< span> 输出1,点击< div>输出2;
- 点击< span>,会先输出1,再输出2;
- 点击< div>,只输出2。
24. Event.target和Event.currentTarget.
我的回答: 听到个Event.target,另一个听成了Event.parentTarget....
总结的回答: Event.target:目标对象(事件触发元素) Event.currentTarget:绑定事件的对象(绑定事件的当前元素)
25 浏览器事件循环
我的回答: 只说了浏览器的事件循环,没说Node的事件循环:
浏览器中分为同步任务和异步任务,同步任务在主线程上顺序执行,异步任务则进入任务队列,而任务队列分为宏任务和微任务。
- 同步任务执行完,检查任务队列,若有宏任务和微任务,先执行微任务,再执行宏任务;
- 如果执行微任务的过程中,产生了微任务,就加入到微任务队列,并按顺序执行,直到所有的微任务执行完后,再去执行宏任务;
- 如果执行宏任务的过程中,产生了微任务,就等当前宏任务执行完后,执行微任务,直到所有的微任务执行完后,再执行宏任务。
26 宏任务和微任务
我的回答:
浏览器宏任务:I/O、setTimeout、setInterval、requestAnimationFrame
浏览器微任务:Promise.then .catch .finally、MutationObserver
Node宏任务:I/O、setTimeout、setInterval、setImmediate
Node微任务: process.nextTick、 Promise.then .catch .finally
宏任务包括:
MacroTask | 浏览器 | Node |
---|---|---|
I/O | ✅ | ✅ |
setTimeout | ✅ | ✅ |
setInterval | ✅ | ✅ |
setImmediate | ❌ | ✅ |
requestAnimationFrame | ✅ | ❌ |
微任务包括:
MicroTask | 浏览器 | Node |
---|---|---|
process.nextTick | ❌ | ✅ |
MutationObserver | ✅ | ❌ |
Promise.then catch finally | ✅ | ✅ |
27. 对Promise的理解
我的回答: 异步编程的一种方案,优化回调地狱 Promise接收两个参数(resolve,reject),这两个参数都是函数;有三个状态:pending进行中,fulfilled成功,rejected失败,返回的结果也是Promise对象, 状态只能改变一次。
28 Promise静态方法
我的回答: Promise.all和 Promise.race
29. ES6新特性
- let、const
- class
- 解构赋值
- 箭头函数
- promise
- async和await
30. let和const 与var的区别
我的回答:
-
有变量提升,存在暂时性死区,提前使用会报错;
-
有块级作用域,var则没有;
-
不能重复声明变量;
-
const声明变量必须赋值,声明的常量不可修改,声明的对象可以修改属性。
31. for...of与for...in
我的回答: for...of:遍历数组,不能单独遍历普通对象,需要借助Object.keys() for...in: 遍历可迭代对象的属性名,不推荐遍历数组
32. HTTP状态码
我的回答:
1. 200:OK //返回成功
2. 301:Moved Permanently //永久重定向
3. 302:Found //临时重定向
4. 304:Not Modified //资源未修改,使用协商缓存
5. 307:Temporary Direction //与302类似,临时重定向,使用GET方式
6. 400:Bad Request //请求报文出现语法错误
7. 401:Unauthorized //未登录,需要请求认证
8. 403:Forbidden //无权限访问,被拒绝
9. 404: Not Found //资源不存在
10. 408:Request Time-out //请求超时
11. 500: Internal Server Error //服务器内部错误
12. 503: Service Unavailable //服务器繁忙或维护(请求太频繁)
13. 505:HTTP Version not Supported //不支持请求的HTTP版本
33. 强缓存和协商缓存
34. 为什么需要三次握手
我的回答:
第一次:证明客户端可以发送数据;
第二次:证明服务器可以接收数据和发送数据;
第三次:证明客户也可以接收数据。
35. BFC
我的回答: Block Formatting Context,用处解决统一父元素的两个盒子外边距重叠问题;
触发条件:
-
body根元素(最大的BFC);
-
position:absolute或fixed;
-
display(inline-block table-cell table-caption flex);
-
float不为none;
-
overflow不为visibility(hidden,scroll,auto,inherit)。
36. Flex
-
flex-direction:定义主轴的方向:
row (默认值):水平方向,从左边开始。 row-reverse:水平方向,从右边开始。 column:垂直方向,从上往下。 column-reverse:垂直方向,从下往上。
-
flex-wrap:项目是否换行:
nowrap (默认值):不换行。 (1,2,3,4,5,6) wrap:换行,第一行在上面。 (1,2,3,4) (5,6) wrap-reverse:换行,第一行下面。 (5,6) (1,2,3,4)
-
flex-flow: (flex-direction) (flex-wrap)。 默认值:row nowrap
-
justify-content: 项目在主轴上的排列方式
- flex-start:左对齐
- flex-end:右对齐
- center:居中
- space-between:两段对齐,项目之间的间隔相等,及等分
- space-around:每个项目两侧的间距相等,所以项目之间的间距是边缘两倍
-
align-items:项目在交叉轴上的对齐方式
- flex-start:交叉轴起点对齐
- flex-end:交叉轴重点对齐
- center:交叉轴中点对齐
- baseline:第一行文字基线对齐
- stretch:默认值,未设置高度或设置auto,占满容器
-
align-content:多跟轴线时,项目在交叉轴上的对齐方式(一根轴线,该属性无效)
- flex-start:左对齐
- flex-end:右对齐
- center:居中
- space-between:两段对齐,项目之间的间隔相等,及等分
- space-around:每个项目两侧的间距相等,所以项目之间的间距是边缘两倍 参考justify-content
37. 左侧定宽,右侧宽度自适应
我的回答:
- 左边设置宽高,左浮动;右边只给高度,宽度100%,margin-left:左边盒子的宽度;
- 父级display:flex,左边左边设置宽高,右边只给高度,宽度100%;
- 定位,左边绝对定位,右边只给高度,margin-left:左边盒子的宽度;
- BFC,左边浮动,右边overflow:hidden。
38. TypeScript
我的回答:用得不多,做react项目用到了泛型和接口,写代码时检测错误,规范编码。
39. 反问
对实习生的要求
学习方法
最后
总体上来说,这些知识点基本上都是知道的,但是没有答得太完整,这次没进,努力两个月,等秋招再来。加油!