前端面试总结----冲冲冲!!!!
这几天面试下来总结了一下面试官问的问题,没想到这么多,汗~~~
以下内容存属于个人面试情况,每个人的情况都不一样,看到的伙伴大概看看就行~
不管是电话,腾讯会议,还是现场面试,免不了的第一个问题
一.你先做个简单的自我介绍?
示例:面试官,你好,我叫XXX,从事前端工作有X年了,之前主要是用vue技术栈实现后台管理系统,h5页面,小程序的开发,平常呢喜欢逛些技术网站,有时也会记录一些工作心得和总结(比如现在,哈哈~),我性格比较随和,工作就喜欢全心全意投入,认真的完成每个项目,以上是我的介绍,谢谢!
二.那你介绍一下你最近或你认为做的比较好的一个项目?
这个问题那必须要提前准备一下,把工作中写过的页面,需求都要准备好,最好理清整个项目的流程是怎么运转的.(这里最好拿最近写的项目,因为脑袋里比较有印象)
示例:嗯,就拿我最近的一个项目来说吧,项目名称是xxxx,主要是一个后台管理服务网站,用于内部员工流程上的操作,比如发起流程,提交,复核,审核等环节,我主要负责宣传推荐词库,新合同,招募书,定期报告,审批进度表等页面,该项目主要用的技术包括:vue,vuex,ckeditor,nprogress,iview,vue-router等技术
以上两个问题问完之后那就会直接进入主题问技术方面的问题了,每家公司,每个项目组问的问题也不一样,可能会根据你的简历挨个问,也可能现场发挥问
三.项目中用到vue-router,那路由传参方式知道哪些啊?
1.params,在path或router-link to后加参数,
在路径中配置path/:id在router-link中配置<router-link :to="`/home/${id}`"><router-link>编程式配置this.$router.push({path: `/home/${id}`})或 this.$router.push({name:"home",params:{id:222}});获取params参数:this.$route.params.id
2.query在router-link to后的?加参数
在router-link中配置<router-link :to="/home?name='lily'"><router-link>在query参数中携带<router-link :to="{path:'/home',query:{name:'lily'}}"><router-link>编程式配置this.$router.push({path:'/home',query: {name:'lily'}})获取query参数this.$route.query.name
3.props,利用props声明接收
props(route){return{...route.params,...route.query}}
四.vue中的通信方式有哪些?
1.项目中通过用的较多的就是props,父向子通信
parent组件:
<Child :message="hello"/>
child级件:
<p>{{message}}<p>
props:{message:String
}
2.若子组件想要向父组件传递数据,就可以通过自定义事件
子组件:
<button @click="go">按钮</button>
export default{name:"Child",data(){return{msg:"hello"}}methods:{go(){this.$emit('change',this.msg)}}
}
父组件:
<Child @change="back"></Child>
export default{data(){return{val:""}}methods:{back(val){this.val=val}}
}
3.若是兄弟组件通信,可以通过全局事件总线,在main.js文件中配置
new Vue({render: h => h(App),//创建之前把bus添加到vue的原型上beforeCreate () {Vue.prototype.$bus = this},
}).$mount('#app')
//组件中若要使用
//a组件传递数据
go(){this.$bus.$emit('change',{age:20})
}
//b组件触发事件
mounted(){this.$bus.$on('change',(res)=>{this.val=res})
}
//注册的总线事件要在组件销毁时卸载,否则会多次挂载,造成触发一次多个响应的情况beforeDestroy () {this.bus.$off('change', (content)=>{console.log(content);});}
4.祖孙组件间通信方式可以通过provide,inject
//祖先组件
//定义好要传递的数据
provide(){return {parentValue:"hello"}}//子孙组件//接收数据//inject:["parentValue"]//或者这种方式接收inject:{parentValue: {from: 'parentValue',default: 'parentValue'}}
5.slot插槽传递带标签的数据
//1>默认插槽
//父组件:
<Child>面试通过了吗?</Child>
//子组件:
<div>//使用slot就可以把"面试通过了吗?"显示出来<slot></slot>
</div>
//2>命名插槽
//父组件
<Child><div slot="top">秃顶?</div><div slot=="bottom">鞋底?</div>
</Child>
//子组件
<div><slot name="top"></slot><slot name="bottom"></slot>
</div>
//3>作用域插槽
//父组件
<Child>//父组件可以接收子组件的数据<template slot-scope="childList">{{ childList }}</template></Child>//子组件<div>//把数据传递给父组件<slot :childList="list"></slot>
</div>
6. p a r e n t 或 parent或 parent或children可以获取父组件或子组件的数据
7.若是多个组件共用的数据,可以通过vuex存储数据
四大核心:state,mutations,actions,getters
state是初始化数据,
mutations是做同步操作,用于直接操作数据
actions是做异步操作,用于间接操作数据,
getters只读性计算属性
组件中要使用时:
import {mapState,mapActions,mapMutations} from "vuex"
computed:{...mapState(['data'])
}
methods:{...mapActions(['getState']),...mapMutations(['getList']),get(){this.$store.state//获取数据this.$store.dispatch('getState',)//触发actions函数this.$store.commit('getList',msg)//触发mutations函数}
}
五.既然提到通信方式,若iframe里面嵌套两个页面,那和iframe外面的的组件如何与iframe里面的页面通信呢?
//postMessage是window上面的方法,这是面试官告诉我的,因为我以前没有用过这个不是很了解//常用于获取嵌入页面中的第三方页面的数据,一个页面发消息,另一个页面判断来源并接收消息1)发送端:window.parent.postMessage('message','http://test.com');2)接收端var mc = new MessageChannel();mc.addEventListener('message',event=>{var origin = event.origin || event.originalEvent.origin;if(origin == 'http://test.com'){console.log('验证通过');}});
六.vue响应式原理有了解吗?
有了解,主要是分为数据代理,数据劫持,模板解析,
1.数据代理:将data中数据代理到实例对象上,遍历所有数据,通过object.definedProperty()方法重新定义属性,内部通过get方法获取数据,set方法设置新值,实际操作是原数据的数据
2.数据劫持:遍历所有data中的数据,将其定义为响应式数据,通过object.defineProperty重新定义get和set方法,这个时候通过闭包可以保存一个dep对象,get中将来通过dep会建立响应式联系,set可以触发响应式更新
3.模板解析
(1)将元素节点转换成文档碎片节点
(2)解析模板
取出当前节点进行遍历,判断是元素节点还是文本节点
若是元素节点就要编译,并且取出所有属性,判断是否是指令属性,若是再判断是否是事件指令
若是,就给元素绑定事件,回调函数可以通bind方法强制this指向
若是普通指令,new watcher触发响应式联系
若是文本节点,就解析插值语法
(3)将解析完的模板代码添加到页面中生效
七.那双向数据绑定原理呢?
是通过v-model实现数据绑定,修改数据时,视图会更新
比如说,给input标签绑定value属性和input事件
当用户输入数据时,会触发input事件,将data中值为e.target.value,实现双向数据绑定
七.项目中是怎么解决跨域的?还知道哪些方法吗?
1.我们项目中用的cors,服务端设置Access-Control-Allow-Origin
2.jsonp是通过创建script标签,src属性添加一个回调,再把script标签添加到body中
3.proxy数据代理在vue.config.js文件中配置,devserve对象中设置
4.项目上线是用nginx后端去配置即可
八.那为什么存在跨域问题呢?
违背了同源策略,所谓同源就是域名,协议,端口号,都一致的情况
http://www.company.com:80,http:是协议,www.company.com是域名,80是端口号
九.项目中用到的性能优化方案
1.使用语义化标签,结构清晰,维护方便
2.减少dom的操作,可以用innerHTML代码dom的操作,优化js性能
3.css中设置样式时不直接设置行内样式,而是使用添加类别进行添加样式
4.少用全局变量,路由懒加载,懒加载,提高用户体验,
5,避免使用table,因为table需要等内容全部下载之后才会显示出来,比div速度慢
6.使用缓存组件,v-if和v-for不能连用
十.移动端适配你有了解吗?
viewport,rem
以下公式可以实现
<meta name="viewport" content="width=device-width/>
1.动态获取窗口宽度
var width=document.documentElement.clientWidth;
var remFontSize=width/10
//赋值给屏幕样式
document.documentElement.style.fontSize=remFontSize+"px"
//最后在css样式中设置相应的rem样式
公式:设计稿宽度/remFontSize(375/37.5=10)
img{width:30/remFontSizerem;height:5/remFontSizerem}2.var remFontSize = (document.documentElement.clientWidth * 100) /375document.documentElement.style.fontSize = remFontSize + 'px'
img{width:30/100rem;height:50/100rem}
十一.深度克隆和浅度克隆的方法
深度克隆的方法1.const newObj=JSON.parse(JSON.strigify(obj))2.function checkType(obj){return Object.prototype.toString.call(obj).slice(8,-1)//获取原型上的方法并借对象}function deepClone(obj){let re;if(checkType(obj)===object){re={}}else if(checkType(obj)===Array){re=[]}else{return obj}for (let in obj){re[i]=deepClone(obj[i])}return re}
3.浅度克隆
let obj=Object.assign(a)
十二.工作中遇到的问题?
(根据自己的项目情况分析即可)
1.前段时间写了一个下拉选项,三级数据的那种,需求是如果二级和三级数据一样那就只显示三级,二级不显示,三级数据有的是单个的,有的是多个的,首先写好树型结构,循环数组,用一个标识识别是二级还是三级,然后判断让谁显示或隐藏,这是比较简单的,但是新增的需求是当选择某单个三级或多个三级时,有些数据是需求隐藏的,就是互斥,比如说a下面有a001,a002,b下面有b001,b002,b003,当选择a001时b002不显示,或者当选择b中任何一个,a需要全部不显示,也有的其它需求,就是互斥并不是两两的,它可能是多个之间互斥,然后我想的解决方法是当选择某个数据时然后保存起来与其它数据比较是否是互斥,但是发现其实没有任何的条件可以满足这个需求,因此和后端协商了一下,最终我们把互斥的规则统计好,我在前置页面写固定的规则数据,然后拿这个数据与我选择的数据再进行判断,这样才能实现
2.有个替换按钮,替换文件没有替换成功反而新增一个文件出来,经过检查, 发现替换文件时会添加一个id上去,原本替换之前的文件没有放到其它地方存储,这样只要一替换就会多一个文件出来,所以可以在页面更新方法那里做个判断,判断有哪个字段可以判断是替换成功的,然后把替换之前的文件放到空数组中,把新替换出来的文件显示出来,这样就可以实现了
十三.promise清楚吗?
promise是异步编程的解决方案,解决回调地狱,promise有三个状态,pending,resolved,rejected,调用resolve函数,会由pending状态变成resoved状态,调用reject函数,会由pending状态变成rejected状态,状态只能修改一次,promise它有then方法和catch方法,then方法中return一个值,或是一个promise对象,或没有return,那最终会返回成功状态的promise对象,若return一个失败的promise对象或抛出错误,那会返回失败状态的promise对象,
一般项目中用的比较多的还是async和await,因为它会返回一个promise对象,async是声明函数是异步的,await是只等待promise对象执行,等异步执行完成,这样就可以利用promise的一些方法去判断返回值,若等待的是返回成功状态的promise对象,则就返回promise对象,若是失败状态的则不执行
十四.localStorage和sessionStorage的区别
sessionStorage可以存储5Mb左右的文件,临时性存储,存在内存中,关闭浏览器就失效了,localStorage永久性存储,存储文件大小是20mb,只要用户不清除缓存,可以永久保存,存在硬盘中,项目中一般在设置token也就是用户登录的标识那里,会把token保存在缓存中,以便用户下次无需重新登录,可以从缓存中读取数据了
十五.es6新特性你知道哪些?
解构语法,模板字符串,let,const,箭头函数,模块化,promise,
我一般用的比较多的是解构象,解构数组,通过rest扩展运算符,获取参数,就不会使用arguments获取了
数组的方法(push后添加,pop后删除,unshift前添加,shift前删除,filter过滤,map映射,reduce,split切割数组,join添加变成字符串等)通过模板字符串,对一些数据引入使用,箭头函数这个用的比较多
箭头函数没有this指向,它的this是距离包裹它的函数,若是普通函数或自调用,那this指向window,若是实例化调用,那指向实例化对象,若是隐式调用则this指向上下文对象,若是call,apply绑定那就是call,apply所规定的那个对象
call,apply都是可以this指向的,只是写法上有些不同,call是用逗号隔开参数,apply是用数组隔开参数,还有bind方法也是改变this指向,但没有调用,会返回一个新函数
还有let,const声明变量的方法,都是只能在块级作用域中生效,不能重复声明,const声明了必须赋值,声明的是常量,声明的值是不能修改的,但是let声明的是变量,值是可以修改的
在js中用到var声明变量,是可以重复声明,后面的会覆盖前面的,可以分为全局变量和局部变量
十六.js数据类型有哪些?
基本数据类型包含:string,number,boolean,null,undefined,symbol,bigint
引用,复杂数据类型有:object,function
十七.使用typeof可以检测出哪些数据类型?NaN是什么?还有使用什么方法检测类型呢?
number,string,undefined,boolean,object,function,
NaN检测出为number类型
可以用object.prototype.toString.call()检测出具体的数据类型
[object,Object],[object,Function],[object,Array],[object,Number],[object,String],
[object,Boolean],[object,Undefined],[object,Null],
十八.路由权限控制如何实现?
在全局路由前置守卫完成,首先从vuex中取出token,判断是否有token,
1.若有的话,说明之前登录过,
取出用户数据判断是否存在,
若存在说明之前登录成功过且数据没有问题,直接放行
不存在,说明之前没有登录成功过,需要进行下面步骤
1.1需要验证token是否有效(是否是真实token,且没有过期)
通过发送请求用户数据,此时在拦截器中请求头会携带上了token,后台会自动进行验证token的有效性
1.1.1有效的话,得到用户数据,包含按钮权限数据和菜单权限数据,菜单权限数据需要处理组件,组件需要使用真正的组件,使用递归遍历处理所有菜单,通过router.addRoutes()来动态添加路由,从而路由生效
1.1.2一上来路由只有登录,404,首页等路由配置,其他都没有,所以一上来用户只能访问这些页面,一旦动态添加路由,用户访问的路由就更多了,从而实现路由权限控制
1.2.1失效的话,清空token,跳转到登录页面
2.没有的话,代表用户之前没有登录过
判断要去路由路径是否是login
是就调用next()放行
不是,调用next({path:"/login"})强行跳转到login
有一个对用户体验更好的小功能就是重定向,跳转到login时加上一个query参数redirect,值为to.path,当将来登录成功时,会拿到redirect进行跳转,而不是首页
十九.nextTick的原理知道吗?
在下次dom更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的dom,dom更新时,是异步更新,数据发生变化并不是直接更新dom,而是开启了一个队列,并缓冲在同一事件循环中发生的所有数据改变 ,当js在执行代码时,只有执行完同步代码之后,才会执行异步代码.
二十.图片懒加载实现原理?
通过img的src属性引入图片,但是一进来先不加载,而是设置个自定义属性(data-orc),然后绑定滚动条事件,判断屏幕顶部的距离,获取这个距离之后,当到达临界值时把自定义属性的值赋值给img的src的值
二十一.histroy和hash的区别
hash:带#,不美观,不可以使用锚点功能,兼容Ie8
路由跳转使用window.location.hash
监听使用:window.onhashChange
不会出现404问题,因为hash的参数都在#后面,而#后面的参数发请求不会携带,所以每次请求 地址都是/,不会是404
history:不带#,美观,可以使用锚点功能 ,兼容Ie10
路由跳转使用window.history.pushState
监听使用:window.popstate 事件
出现404问题,开发服务器处理 / 根路径请求,别的路径是处理不了,访问 /home 就会出现 404
devServer: {
historyApiFallback: true, // 一旦请求404,就默认返回index.html页面
}
二十二.jquery和vue的区别
jquery使用选择器$,选取dom对象,对它进行赋值,取值,事件绑定等操作,更方便选取和操作dom对象,数据和界面在一起的
vue将数据和页面分离开了,对数据进行操作不再需要引用相应的dom对象,因为数据都代理到vm实例上,通过this可以直接访问到, 是双向数据绑定,响应式数据,支持组件化,模块化
二十三.响应状态码代码知道哪些?
100请求继续
200请求成功
204请求成功,部分数据更新
206进行范围请求
301永久性重定向
302临时性重定向
303资源存在另一个url,使用get获取资源
304允许访问资源,读取缓存数据
400异常请求,请求参数出错,不存在,语法错误
401认证信息过期,出错
403请求的资源被服务器拒绝访问
404找不到请求的资源
500服务端请求时发生了错误
503服务器无法处理请求
二十四.computed和watch的区别
computed是计算属性,只有依赖的数据发生变化,它就会更新,具有缓存的功能watch是监视属性,数据发生变化,函数会直接更新,没有缓存
二十五.请谈一下原型链?
每个函数都有原型对象,只要是new出来的就是构造函数,构造函数的prototype属性指向原型对象,原型对象上的construct构造器会指回构造函数,构造函数的实例化对象有个__proto__属性会指向构造函数的原型对象,终极链就是obejct的__proto__指向null
目的是就为了实现继承,当查找变量的时候自身上面没有就会沿着原型链查找
二十六.和=的区别?
==会进行类型转换,再进行值比较大小===类型和值都必须都相等,类型和值都会进行比较
二十七.js继承的方法有哪些?
原型链继承,
构造函数继承,
实例继承,
组合式继承,
类继承
二十八.v-if和v-show的区别,应用场景
v-if用于条件渲染,切换会有局部编译和卸载的过程,或者销毁和重构内部事件监听和子组件,切换消耗比较大,条件不大可能改变的情况,项目中一般用于判断有没有这个数据,或id是否相等,用于条件判断
v-show样式属性控制,频繁切换更高的初始渲染消耗,项目中用于组件频繁的切换
二十九.有个数组需要修改数据如何操作
let list=[{name:"lily",task:"working"},{name:"mike",task:"running"}
]
let art1={name:lily,task:"working"}
this.$set(this.arr,0,art1)//这个方法修改数据页面会同时更新
let art2 = { name: 'second', task: '0' };
console.log(this.arr.push(art2));//这个方法修改数据页面也会同时更新
console.log(this.arr[9])//undefined
若数组中是number
let arr=[1,2]
console.log(arr[5])//undefined
console.log(arr[5].push(3))//报错,因为push是往数组中最后一项去添加数据
往数组后添加数据打印结果会怎样?
let arr=[1,2]
console.log(arr[8])//undefined
console.log(this.arr.push(10))//正常显示,视图会更新
console.log(this.arr[0].push(5))//报错,
console.log(this.$set(this.arr,4,5))//正常,视图会更新
打印结果?
console.log(a)//undefined 变量提升
var a=1console.log(b)//报错未定义
let b=2
三十.数组去重方法?
//方法一.filter有三个参数,index,item,self数组自身
arr.filter((item,index,self)=>{return self.indexOf(item)===index
})
//方法二
let arr=[1,2,2,1]
console.log([...new Set(arr)])
//方法三
let arr=[1,2,2,3]
console.log(Array.from(new Set(arr)))
//方法四
var arr=[1,1,2,2,3]
var list=[]
for(var i=0;i<arr.length;i++){if(list.indexOf(arr[i])===-1){list.push(arr[i])}
}
//方法五
for(var i=0;i<arr.length;i++){if(arr.indexOf(arr[i])===i){list.push(arr[i])}
}
//方法六
for(var i=0;i<arr.length;var flag=true;for(var j=0;j<list.length;j++){if(list[j]==arr[i]){flag=false;break}}if(flag){list.push(arr[i])}
}
//方法七
for(var i=0;i<arr.length;i++){for(var j=i+1;j<arr.length;j++){if(arr[j]==arr[i]){i++;j=i}}list.push(arr[i])
}
let a=new Set(arr)
let b=Array.from(a)
console.log(b)
三十一.数组排序方法?
//方法一:
let arr=[3,,6,2,0,5]
arr.sort(function(a,b){return a-b
})
console.log(arr)
//方法二:
function sort(arr){if(arr.length<=1)return arrlet middle=Math.floor(arr.length/2)let point=arr.splice(middle,1)let left=[],right=[]for(let i=0;i<arr.length;i++){if(arr[i]<point){left.push(arr[i])}else{right.push(arr[i])}}return sort(left).concat([point],sort(right))
}
console.log(arr)
三十二.判断字符串中出现次数最多的方法
var str = 'abcdefgaddda';var arr = str.split('');//先转换成数组var newArr = [];var numArr = [];arr.forEach(function (element, index, array) {var index1 = newArr.indexOf(element);if (index1 == -1) {newArr.push(element);numArr.push(1);} else {numArr[index1]++;}})function sortNumber(a, b) {return b - a;}var numArr1 = [].concat(numArr);numArr1.sort(sortNumber);var maxNum = numArr1[0];var index = numArr.indexOf(maxNum);var maxStr = newArr[index];console.log('字符串"' + str + '",' + maxStr + '出现次数最多,次数为' + maxNum);
三十三.vue3的响应式原理和typescript语言
1.通过proxy代理,拦截data任意属性的13种操作,包括属性值的读写,添加,删除等,通过reflect反射,动态对代理对象的相应属性进行特定的操作
2.typescript语言:提供类型系统,js是弱类型语言,typescript是强类型语言,可以编译出简洁的js代码,并可运行在任何node环境中,和任何浏览器中
3.类型:boolean,number,string,undefined,null,Array,元组Tuple[string,number],
enum枚举,any,void,object,联合类型(x:number|string),类型断言,类型推断,
3.接口interfaces,对值所具有的结构进行类型检查,定义对象的类型,可选属性?,只读属性readonly,函数类型,类类型,
4.泛型,是指在定义函数,接口,类的时候,不先指定具体类型,而在使用的使用再指定具体的一种,函数泛型,泛型接口,泛型类,泛型约束,
三十四.深度克隆的方法
1.const newObj=JSON.parse(JSON.strigify(obj))
2.function checkType(obj){return Object.prototype.toString.call(obj).slice(8,-1)//获取原型上的方法并借对象
}
function deepClone(obj){let re;if(checkType(obj)===object){re={}}else if(checkType(obj)===Array){re=[]
}else{return obj
}
for (let in obj){re[i]=deepClone(obj[i])
}
return re
}
三十五.js事件轮询机制
同步代码:绑定事件,定时器,发送ajax
异步代码:事件回调函数,定时器的回调函数,ajax的回调函数
先执行同步代码再执行异步代码
原理:执行完同步代码之后,把相应的回调添加到管理模块中,事件回调添加到事件管理模块,ajax回调添加到ajax管理模块,等事件发生或计时器到期等,就会把相应的回调函数添加回调队列中等待执行,等初始化同步代码执行完毕之后,js引擎会循环检查回调队列中的回调函数,并执行
三十六.路由勾子函数
全局前置守卫beforeEach,全局解析守卫beforeResolve,全局后置钩子afterEach
路由独享守卫beforeEnter
组件内的守卫beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave
三十七.keep-alive的实现
若组件需要缓存,通过keep-alive包裹起来,并设置include或exclude,缓存不活动的组件实例
keep-alive的生命周期顺序:
created–>mounted–>activated—>deactivated–>activeated
三十八.let const var的区别
var是一个变量,声明了可以赋值,也可以不赋值,允许重复声明,存在变量提升,
let和const是由块级作用域包裹,const声明了必须赋值,声明的是一个常量,
let是一个变量, 声明了可以不赋值,声明的值可以被修改
三十九.promise的打印顺序
const promise=new Promise((resolve,reject)=>{console.log(1)console.log(2)
})
promise.then(()=>{console.log(3)
})
console.log(4)
打印结果为:1,2,4
分析:只要没有调用resolve和reject函数,那就不会执行then,catch方法,new Promise里的代码是同步的,和4是一起执行的,但是书写顺序是4之前所以比4先打印,
四十.用递归写一个求1到100的和
//方法一
function getSum(start,end){start+=end;end++;if(end>100){console.log(start)//5050return start}else{getSum(start,end)}}
getSum(0,1)方法二:
function fn(n){if(n==1)return 1return fn(n-1)+n
}
fn(100)
console.log(fn(100))//5050//方法三
function add(a,b){var num=0;for(var i=0;i<=b;i++){num+=i}return num
}
add(1,100)
四十一.for循环打印顺序
for(var i=0;i<5;i++){setTimeout(()=>{console.log(i)// 5 5 5 5 5},200)
}
for(var i=0;i<5;i++){setTimeout(()=>{console.log(i)// 5 5 5 5 5},200,i)
}
for(let i=0;i<5;i++){setTimeout(()=>{console.log(i)// 0 1 2 3 4},200)
}
for(let i=0;i<5;i++){setTimeout(()=>{console.log(i)// 0 1 2 3 4},200,i)
}
四十二.vue的生命周期
beforeCreate,数据代理之前 ,不能访问到this上的数据
created,数据代理之后,可以访问到this上的数据,在模板渲染成html之前调用
beforeMount,数据挂载之前不能操作dom,
mounted,数据挂载之后可以操作dom,绑定事件,计时器等一次性的操作,在模板渲染成html之后调用
beforeUpdate,数据更新之前调用
updated,数据更新之后调用
beforeDestroy,数据销毁之前
destroyed数据销毁之后
四十三.v-for和v-if的优先级比较,v-for中的key的作用
v-for比v-if的优先级高,v-for中的key的作用是提高渲染性能,是唯一的标识,比较虚拟dom和真实dom,高效的更新虚拟dom
v-for和v-if不能在一个标签内使用,若要使用,可以使用
四十四.组件中data为什么是一个函数?
组件是可以被复用的,如果data是对象,那多个组件会共享同一个对象,若一个组件值发生变化,其余组件都会发生变化 ,但是调用函数,每次会产生一个新的函数,这样每个组件的对象都会不一样,每个组件都有自己的数据,所以互不影响
四十五.css,less,和sass的区别
sass是一种动态样式语言,比css多出好多功能 (如变量,嵌套,运算,继承,等)便于阅读,是在服务端处理,变量符是$,支持条件语句,for循环
less是一种动态样式语言,如变量,继承,运算,函数,在客户端上运行,也可以在服务端上运行,变量符是@
sass,less都会编译生成.css文件,之所以用这两种语言是为了便于扩展,功能比css强大
四十六.new操作符做什么?
创建一个空对象,将来返回这个对象;
调用构造函数,并将构造函数的this指向新创建的对象obj
把原型对象的方法给新创建的对象obj,把obj的–proto–指向构造函数的原型对象
判断构造函数的返回值 ,来决定new的返回值(是构造函数的返回值还是实例化对象)
四十七.call,apply,bind的区别
call,apply,bind改变函数的this指向,
call,apply功能一样,但是参数不一样
fn.call(fn的this指向,fn函数的参数,参数与参数之间用逗号隔开)fn.apply(fn的this指向,[数组,里边书写的是fn的参数])fn.bind(fn的this指向,fn函数的参数,参数与参数之间用逗号隔开)
call,apply都是改变了this指向,并调用了函数
bind只是改变了this指向,并返回一个新函数引用,并没有调用函数
四十八.this指向问题
this是根据函数调用时决定的
test() 自调用-----this指向window
obj.test() 上下文对象调用-----this指向上下文对象
事件函数this 指向绑定的事件元素
new test() 实例化调用-----this指向实例化对象
test.call() call调用-----this指向call把规定的对象,若第一个参数为null,则this指向window
递归调用,this指向window
四十九.diff算法,真实dom和虚拟dom的区别
分为两个阶段,
首次渲染时,注入生命周期,通过数据代理,数据劫持将template解析生成render函数,使用render函数生成虚拟dom树,使用虚拟dom生成真实的dom,将真实的dom挂载到页面上;
组件更新渲染时,经过数据代理和数据劫持,触发dep.notify()通盘古watcher进行视图更新,生成新的虚拟dom树,将新的虚拟dom与旧的虚拟dom进行比较,判断哪些真实dom是可以复用的,能复用就复用,不能复用就重新生成新的真实dom,将最新的真实的dom挂载到页面上;
key的作用,当响应式数据发生变化,组件会生成全新的虚拟dom树,并比较新旧两棵虚拟dom树,如果数据包括key相同,复用之前的真实dom,否则重新生成
五十.vue,react,小程序,jquery的区别
vue是双向数据绑定,
获取数据,this.xxx,设置数据this.xxx=xx通过数据代理获取this上的数据,数据劫持修改数据,再通过dep对象通知wathcer更新视图
react是单向数据流,
获取数据,this.xxx,设置数据this.setData({xxx:xxx})持久化存储数据,在生命周期和合成事件中是异步更新,在原生事件和计时器中是同步更新合成事件是指小驼峰命名法的事件,原生事件是全小写
小程序是单向数据流,
获取数据,this.data.xxx,设置数据this.setData({xxx:xxx})持久化存储数据,同步修改异步更新
jquery用于获取dom对象,可以使用链式调用,普通的动态效果切换使用
五十一.http和cookie的关联
http是超文本传输协议,cookie是用于解决服务端和客户端会话状态的问题,这个状态而非通讯协议的状态,cookie是某个网站为了辨别用户身份而存在用户本地终端上的数据,存储文件大小为4kb,由名称,值,有效期,安全性,使用范围的可选属性,设置cookie,客户端发送http请求到服务器,当服务器收到http请求后,在响应头里设置set-cookie的字段,浏览器收到响应后保存cookie,之后对服务器的每次请求都通过cookie将cookie信息发送给服务器
五十二.xss攻击,csrf攻击
xss跨站脚本攻击,攻击者向目标网站注入恶意代码,当被攻击者登录网站会执行这些恶意脚本,这些脚本会读取用户的cookie,token,session或敏感信息,对用户进行攻击,
xss防预,避免使用dom,严格过滤回调后的参数并限制长度,进行字符,标签转义操作
csrf跨站请求伪造,是攻击者诱导用户进入第三方网站,然后向被攻击网站跨站发送请求,利用受害者在被攻击网站获取凭证,经过后台用户验证,达到冒充用户对被攻击的网站进行操作的目的
csrf防预,增加验证码,判断请求来源,使用token
五十三.vue的事件修饰符有哪些?
stop,阻止冒泡
prevent,阻止默认行为
capture,捕获
self,自身事件
once,触发一次
passive滚动事件的默认行为立即触发
五十四.路由传参方式
1.params,在path或router-link to后加参数,
在路径中配置path/:id在router-link中配置<router-link :to="`/home/${id}`"><router-link>编程式配置this.$router.push({path: `/home/${id}`})或this.$router.push({name:"home",params:{id:222}});获取params参数:this.$route.params.id
2.query在router-link to后的?加参数
在router-link中配置<router-link :to="/home?name='lily'"><router-link>在query参数中携带<router-link :to="{path:'/home',query:{name:'lily'}}"><router-link>编程式配置this.$router.push({path:'/home',query: {name:'lily'}})获取query参数this.$route.query.name
3.props,利用props声明接收
props(route){return{...route.params,...route.query}}
五十五.数组拉平的方法有哪些?
let arr=[[1,2],[3,4],[5,6]]
1.let list=[]
arr.forEach(item=>{item.forEach(val=>{list.push(val)})
})2.let newList=arr.flat(1)
3.let newList = [].concat(...arr)
4.let newList = [].concat.apply([], arr)
五十六.父组件中有个子组件,生命周期是怎么执行的?
1.未设置条件的情况下:
父组件created—>父组件beforeMount—>子组件created—>子组件beforeMount—>子组件Mounted—>父组件Mounted
2.设置了v-if,v-show都为true的情况,生命周期如上一样
3.设置了v-if,v-show都为false的情况,最后会增加两个生命周期,父组件beforeUpdated–>父组件updated
五十七.display:flex布局属性的使用
flex-direction:主轴方向row/column;
flex-wrap:换行wrap/nowrap
flex-flow是flex-direction和flex-wrap的简写形式
justify-content主轴对齐的方式flex-start/flex-end/center
align-items交叉轴对齐
align-content多根轴线对齐
order排列顺序
flew-grow:放大比例,存在剩余不放大
flew-shrink:缩小,空间不足,会缩小
align–self:继承align-items
五十八.转为真数组的方法
1.[].slice.call(arguments)
2.Array.prototype.slice.call(arguments)
3.Array.from(arr)
4.[...arr]
五十九.遍历对象的方法
let obj={name:"lily",age:20}1.for(let i in obj){console.log(i)//name,age取key值
}
2.Object.keys(obj)//['name','age']//取数组形式的下标对应的值
3.Object.getOwnPropertyNames(obj).forEach((item)=>{console.log(item,obj[item])//name lily age 20
})
console.log(Object.getOwnPropertyNames(obj))//['name','age']
五十九.for…in 和for…of的区别
for…in遍历对象,取key值,不能遍历数组,返回可枚举的属性,遍历整个原型链
for…of遍历数组,伪数组,有iterator对象遍历
六十.0.1+0.2!=0.3为什么?
(这个问题的答案还是很模糊)
符点数的操作,因为符点数在存储的时候可能出现不能准确转化为对应的2进制的情况,在计算过程中可能存在大数吃小数的情况,也会导致数据不准确;因为存储方式不一样,科学技术法,用定点数存储数据
六十一.从输入url到解析出页面 中间经历的过程
1.DNS解析:解析域名得到服务器的公网IP,从而能访问服务器
DNS缓存:
浏览器缓存
计算机缓存
路由器缓存
运营商缓存
2.TCP三次握手:建立连接,确保双方发送和接收能力正常
a.客户端向服务端发送数据包,服务端收到数据包,说明客户端的发送能力正常
b.服务端接收到数据包之后,向客户端发送数据包,客户端接收的服务端的数据包之后,说明服务端的接受和发送能力正常
c.客户端继续向服务端发送数据包,服务端接受到数据包之后,说明客户端的接受能力也正常
3.发送请求
按照HTTP协议的规定,生成请求报文,浏览器将请求报文发送给服务器
4.服务器返回响应
按照HTTP协议的规定,生成响应报文,服务器将响应报文发送给客户端
5.渲染页面
渲染页面的过程:
1.解析html生成DOM树
2.解析css生成CSSOM树
3.解析js,可能会对DOM和样式修改
4.根据DOM树和CSSOM树,生成渲染树(render Tree)
5.分层:根据层叠上下文属性,将渲染树的节点进行分层
6.生成图层绘制指令
7.栅格化:将图层划分为图块
8.合成和显示
6.TCP四次挥手,断开连接
1.客户端发送数据包,表示请求数据发送完毕
2.服务端接受到客户端的释放信号,向客户端发送数据包,表示已经接收到客户端发送的释放信号
3.服务端的数据发送完毕后,会主动给客户端发送数据包,表示服务端的响应数据发送完毕
4.客户端向服务端发送数据包,表示收到
前端面试总结----冲冲冲!!!!相关推荐
- 前端面试官,我为什么讨厌你。
近两年来,参加过的前端面试不下二十场了,吐槽一下.我所经历的,都是小公司,大公司的同学请无视. 招聘信息能否不要装逼?写一大堆你项目根本用不上的,来给谁看?我曾遇到上面写了一堆对js如何要求,对mv* ...
- 前端面试的作品示例_如何回答任何技术面试问题-包括示例
前端面试的作品示例 Technical interviews can be extremely daunting. From the beginning of each question to the ...
- Web前端面试自我介绍对话技巧注意事项
大家在学会了web前端技术后,当然是要准备找一个适合自己的web前端工作了,那么面试环节是必不可少的,有一个良好的自我介绍表述,在HR心中也能加分不少,接下来小编就为大家介绍一下Web前端面试自我介绍 ...
- 那些巨头公司的前端面试都喜欢问些什么?
在过去的几年里,我在亚马逊和雅虎面试过很多专注于前端开发的Web开发者和软件工程师,在这篇文章中,我想分享一些面试技巧,帮助候选人为面试做好准备. 免责声明--本文并非旨在列出在前端面试中可能会被问到 ...
- 前端面试查漏补缺--(一) 防抖和节流
前言 本系列最开始是为了自己面试准备的.后来发现整理越来越多,差不多有十二万字符,最后决定还是分享出来给大家. 为了分享整理出来,花费了自己大量的时间,起码是只自己用的三倍时间.如果喜欢的话,欢迎收藏 ...
- 校招社招必备核心前端面试问题与详细解答
本文总结了前端老司机经常问题的一些问题并结合个人总结给出了比较详尽的答案.网易阿里腾讯校招社招必备知识点. 原理讲解参考:前端增长-重新定义大前端 在线课程:网易云课堂课程 思否课堂 官方博 ...
- HTML5学习路线资料,HTML5前端面试的技术栈
各位小伙伴大家好,现如今前端程序员编程可是相当的吃香.根据多年丰富的面试经历和岗位分析,对前端面试的技术栈,各大公司面试特点,进行简要的分析 ,随着我的秀发越来越少可以说我们积累的经验越来越多,在此给 ...
- 【前端面试分享】- 寒冬求职下篇
前言 越来越多的公司都在面试前加入了笔试环节. 有的甚至会根据你的笔试答题情况来决定是否进入面试环节. 当然,进入面试环节,也会时不时的出几道算法或者其他类型的相关的题目让你写出来. 所以不仅要会说, ...
- 问得最多的十个JavaScript前端面试问题
我知道有很多人不同意这种类型的面试.其实不管你喜不喜欢,你都得接受.尤其当你是自学的,而且要申请第一份工作时. 我估计很多有人其它方法来证明他自己,像Github/ 项目地址可能是非常理想的证明方法, ...
- 前端面试-综合问题版
一.基础 #1.1 HTML html5新标签有哪些 canvas.svg.webGL 你是如何理解 HTML语义化的,有什么好处 前端需要注意哪些SEO? manifest.worker.socke ...
最新文章
- java8 迭代set集合_JavaSE(八)集合之Set
- 【软件体系结构】软件体系结构复杂性
- c语言多线程面试题,iOS面试题--网络多线程
- c语言switch结构计算利润,求助。。关于用switch编写简易计算器
- winformbutton边框怎么改_C#(winform)为button添加背景图片,并去掉各种边框
- zabbix-设置邮箱预警
- windows系统远程桌面相关内容
- Python实现WGS 84坐标与web墨卡托投影坐标的转换
- makefile编写---:= ?= += =的区别
- 西子奥的斯服务器显示dlf,OTIS奥的斯XIOTIS西子奥的斯E311故障查询和故障代码(全).pdf...
- 解决高并发(数据库锁机制)
- 如何提高睡眠质量快速入睡,改善睡眠的小妙招你要知道
- Android版本与SDK 版本对应关系
- IOS开发—iOS视频拍摄与压缩
- 深度学习(一):给你的数据集打标签
- Redis基本使用|基本命令|redis事务|Jedis|持久化|订阅|集群|
- 如何获取ffmpeg返回的错误信息
- 专利申请需要缴纳的费用
- 基于DS1820与DS1302的控制装置(窗帘控制)
- 整理汇总了一份常用的 Linux 软件!
热门文章
- 如何将旧笔记本电脑显示屏魔改扩展屏-2021-05-26
- 用友账套和报表服务器显示不同,用友T6不同账套中报表汇总
- 基于Java开发一套完整的区块链系统
- Cool Website
- 有效字符区域 获取textview_Android之TextView 详细字典
- html播放mov格式视频,video - ffmpeg将mov文件转换为mp4,用于HTML5视频标签IE9 - 堆栈内存溢出...
- Java:在Java中调用python文件执行
- AP Autosar平台设计 9 诊断
- 高效能程序员的修炼读后感
- 达梦数据库8自动备份教程