可能问到的问题
Vue 相关的面试题
-
diff 算法 https://github.com/answershuto/learnVue/blob/master/docs/VirtualDOM%E4%B8%8Ediff(Vue%E5%AE%9E%E7%8E%B0).MarkDown
1.VUE 将真实 DOM 抽象成 虚拟 DOM
2.当数据发生改变的时候,通过 diff 算法比较 虚拟DOM 的变更
3.然后再更新视图,减少很多 DOM 操作,节省性能
4.diff算法是通过同层的树节点进行比较而非对树进行逐层搜索遍历的方式,所以时间复杂度只有O(n) -
axios 是如何实现
axios是基于promise封装的 http 库 -
登录控制
- 路由拦截:登录的时候用路由拦截,
beforeEach(to, from, next)
这个函数进行判断,如果用户有登录,那就会更新 vuex 里的数据,在拦截函数里面通过vuex state获取当前的token是否存在 - http 拦截器:没带上 token 就返回 401,让用户登录
- vue-router 钩子
全局
router.beforeEach((to, from, next) => {})
router.afterEach((to, from) => {})
组件上的配置
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
-
vue-router 原理
利用 hash #,window.addEventListener("hashchange", funcRef, false)
HTML5 的 History.pushstate() -
history 和 hash
我用原生 js 实现过这两种方式的 spa 路由,都是放置一个空的 div 标签作为路由出口 -
hash 模式是监听 haschange 事件,或者监听 a 标签的点击事件,通过 location.hash 去拿到 url 里的路径和和 hash 值,在解析之后将对应的 dom 内容插入到路由出口
-
history 模式是也可以通过 a 标签的点击事件,事件里面要用 preventDefault 取消跳转行为,通过 history.pushState 将要跳转的路径存入 path 参数,通过 location.pathname 取 path,location.search 取url 里的参数,解析之后返回对应 dom 内容,插入到路由出口
1.绑定 a 标签事件
2.取 path 和 参数
3.将内容插入到路由出口
- 怎么实现自定义指令
全局自定义指令
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
局部自定义指令
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
-
v-for 为什么要用 key
key 是每一个vnode的唯一id,添加 key 之后可以更快更准的进行虚拟 dom 的比较, 加快性能 -
vue 数组是怎么实现双向绑定的
defineProperty 不能监听数组, vue 采用的方法是重写了 数组的几个常用的api
以及vue 的 set api -
vue 3 是怎么解决这个问题的?
使用 es6 提供的 Proxy 的 api,优势是直接对对象的操作进行一个监控, 不需要 defineProperty 对每个属性都做一次 getter setter的设定. 同时 Proxy 也支持对数组的监听 -
有了解过 slot, vue 2.6+ 添加的新的 slot api 有使用过?
在创建公共组件的时候, 经常使用slot. slot 是一个插槽, 主要在公共组件使用中, 通过设置slot, 在不同的部分显示不同的内容. 2.6的提供新的语法糖, 在项目中我没有用过, 但是我可以简单说一下这个语法糖的特点是, 把 slot 和 slot-scope 的组合在一起的用法 -
使用过 vue 的 mixin 操作, 这个有什么缺点可以说说?
A: 使用过, mixin 是 vue 里面的继承功能, 例如一个 js 文件定义了 methods 属性, 里面有5个方法, 在一个新的 vue 文件中, mixin 这个文件, vue 文件就会继承了这 5 个方法了, mixin 的缺点有, vue 文件可以覆盖之前的方法属性, 第二个是使用了 mixin 的方法后, ide 不能提示相应的方法 -
公共组件怎么编写的
- 计好与父组件的通信
- 符合 UI 要求,并且留好后续定制 UI 展示的空间
- 写好使用文档
写公共组件我会先想好父子组件之间的通信,如果子组件里面要改变父组件的数据,比如一个短信验证码的输入框组件,我会用 sync 修饰符,然后在子组件里面用 watch 监听这个传入的属性,在监听函数里面把 update 时间 emit 出去。然后是按照 UI 要求去写样式,设置默认样式,然后留好灵活设置的余地,最后是写好使用文档,不仅是代码文件里写注释,word 文档里面也有记录,就是组件的截图,以及名称,这样新人一来,在接到需求的时候可以快速查阅使用。
- 其他
https://juejin.im/post/5d41eec26fb9a06ae439d29f
https://juejin.im/post/5d59f2a451882549be53b170
生命周期 https://segmentfault.com/a/1190000008010666
HTML 5
- DOM API document.querySelector()
- Storage
- 语义化标签、图形标签 svg canvas、多媒体标签 video audio source
- 新增的input的type类型和属性
CSS3
-
两栏布局
float 和 flex -
清除浮动
浮动元素的父元素后面加一个 伪元素 after,display block,content '',clear: both
-
画三角形
width: 0;height: 0; border: 40px solid; border-color: transparent transparent red transparent transparent;
-
居中:
1.用 flex, align-items:center,content-justfy: center
2.css3 的 transform,translateX(-50%), translateY(-50%) -
最常用的一个构造函数
function Person(a,b,c) {
this.a = a
this.b = b
this.c = c
this.friends = [1,2,3]
}
Person.prototype = {
constructor: Person,
sayName: function() {
console.log(this.a)
},
}
- 最常用的继承
function Man(a,b,c,d) {
Person.call(this, a, b, c)
this.d = d
}
Man.prototype = new Person()
Man.constructor = Man
Man.prototype.logD = function() {
console.log(this.d)
}
- class
// 定义类
class Point {
// 构造函数
constructor(x, y) {
this.x = x;
this.y = y;
}
get prop() { // Point.prop 的 getter 函数,调用时返回值
// do something
return 'hahaha'
}
set prop(value) { // Point.prop 的 setter 函数,在赋值的同时执行
console.log('设置 prop 为' + value)
}
static method1() {
// 一个静态方法,不会被实例获取的,但是会被子类继承调用
console.log('静态函数 method1,可被类调用,不可被实例调用')
}
method2() {
console.log('这里是 method 2,可被实例调用,可被子类继承')
return '(' + this.x + ', ' + this.y + ')';
}
}
// 继承类
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y) // 调用父类的constructor(x, y)
this.color = color
}
method3() {
return this.color + ' ' + super.method2(); // 调用父类的toString()
}
}
- 性能优化
- 压缩图片大小,以及文件大小
- 合并请求,一个接口能做完的事不要用两个接口
- 静态资源使用缓存策略(强制缓存和协商缓存)、使用 cdn
- 预判用户行为,对资源进行预加载(查看用户协议)
- 传统的:如果是不使用框架的原生js项目, 就是js文件放底部,使用雪碧图、尽量减少 dom 操作,使用事件委托
-
地址栏输入地址浏览器发生了什么
https://zhuanlan.zhihu.com/p/23155051 -
script async deffer
浏览器在渲染一个页面的时候,遇到 <script> 标签就会先下载然后执行,如果资源文件比较大或者文件下载了下来之后执行时间比较长,页面响应就会比较慢,影响用户体验。使用这两个属性可以使 js 文件的执行阻塞页面的情况得到优化,区别是 deffer 是立即下载,然后在文档解析之后执行,async 是异步加载,加载之后立即执行,所以如果 js 文件有依赖关系,应该避免使用 async ,因为有可能因为找不到依赖而报错 -
闭包
我个人的理解是,cpu 在执行函数的时候,会在内存里给这个函数分配一块栈空间,传入这个函数的参数以及在函数内定义的变量都会存入这个栈空间,当函数执行完毕的时候,变量被销毁,栈空间被还原。但是如果在这个函数里再定义一个函数,并且这个函数用到了外层传入的参数或者变量,在外层函数执行完之后,内部函数用到的变量并不会被销毁,而是依旧保存在栈空间中。所以过度使用闭包,会导致栈溢出,也就是stackoverflow
网络安全
-
xss
常见的就是在发布评论的时候提交恶意 js 代码,如果没有进行过滤或者转义,其他用户在访问页面的时候这些恶意 js 代码就会执行
防范:HttpOnly 防止劫取 Cookie,前端进行输入检查,后端进行输出检查 -
xsrf
窃取 cookie 信息,冒充用户伪造请求,删帖、转帐、改密码、发邮件全都可以伪造
防范:验证码(手机短信、滑动图片),加 token
ES6 直接看笔记
- 浏览器的渲染过程
浏览器下载完所有页面组件(html,css,js,图片)后会生成两个内部数据结构:
1.DOM 树,表示页面结构
2.渲染树,表示 DOM 节点该如何显示(对应到 css 就是盒子模型)
高程笔记
https://github.com/theLongGoodbye/read-GaoJiChengXuSheJi
http
-
http1.0 和 1.1 的区别
keep-alive,更多的缓存控制策略,支持断点续传 -
keep-alive 为什么可以节省资源
http1.0的时候, 每次请求资源都要, 经历创建tcp连接, 发送数据, 销毁tcp连接, http 1.1增加了keep-alive ,重复使用一个tcp连接, 节省资源, 加快访问数据 -
http 缓存的功能
客户端和服务端通过 请求和响应 的报文来实施缓存策略,分为:
1.强制缓存,当缓存数据库中已有所请求的数据时,直接从缓存数据库获取数据
2.协商缓存(对比缓存),浏览器会先发请求问服务器这个缓存的资源有没有变,没变就是304,变了就重新获取资源
报文字段包括:http1.0 时期的 Expires,http1.1 的 Cache-Control,Last-Modified - If-Modified-Since、Etag - If-None-Match -
三次握手
-
说一下 cors 是什么?
A: cors 是一个跨域的解决方案, 在访问跨域资源的时候,浏览器会会添加头信息,如果是简单请求(get post head或content-type 是 text/plain multipart/form-data),会加上 origin(域名端口协议),非简单请求先发送optings检测服务器是否能跨域,返回200再返送后面的http 请求,服务器接收到这些字段之后,决定是否正常响应这次请求,如果同意,响应报文里会有 Access-Control-Allow-Origin 字段
- cors可以带上cookie?
A: 可以, 前端需要设置 withCredential 为 true, 后端的 Access-Control-Allow-Origin 的内容是具名的地址, 不能是 *
- websocket
基于TCP传输协议,某些业务场景下,要求客户端和服务器能同时向对方发送消息,如果用其他的方法比如用 ajax 轮询非常消耗资源,而且轮询的时间并不可靠,所以出现了 websocket,大致的做法是,在客户端创建一个socket实例并且提供要连接的服务端的IP地址和端口,然后在服务端创建另一个socket实例并绑定本地端口进行监听,两端连接之后双方建立了一个端对端的TCP连接,实现双向通讯
- 冒泡排序
function sort(element){
for(var i = 0;i<element.length-1;i++) {
for(var j = 0;j<element.length-i-1;j++){
if(element[j]>element[j+1]){
let temp= element[j];
element[j] = element[j+1];
element[j+1] = temp;
}
}
}
- 爬楼梯
const climbStairs = function(n) {
if(n == 1) return 1;
if(n == 2) return 2;
return climbStairs(n-1) + climbStairs(n-2);
};
const climbStairs = function(n) {
let a = b = 1;
for (let i = 0; i < n; i++) {
[a, b] = [b, a + b];
}
return a;
};
为什么离职
自我介绍
你好,我来自江西,在广州工作7年了,其中3年是前端开发
大学毕业之后做的是文案策划,后来在工作中因为接触到了前端这一块的工作内容
经过学习和了解之后觉得编程很有意思,然后互联网的发展前景也更大,就决定自学转行
自学了一年多觉得各方面技能都差不多了就转行了
到现在做了3年前端,目前是在广发银行研发总部给他们的手机银行App开发各种需求
我虽然是半路转行,也不是科班,但因为工作这些年一直持续的学习、练习和追赶
前端开发工作中需要掌握的技能我都掌握的很好,擅长使用的框架是 vue 、angular 和 jQuery
我做事注重习惯和规范,所以开发效率很高,质量也有保障
我的情况大概就是这样
为什么离职
1.公司项目进入成熟稳定期,所以想看看有没有技术挑战更大一些的工作机会
你有什么优点
编码效率高
当自己的事
网友评论