前端面试题总结

以下为2020年8月前端面试的真实提问,每从1开始都是新的公司,处于对公司的尊重,未公开公司名,请诸君与我一起共勉!

1.实现多个具有数据依赖的异步请求加载?promise原理?

1.可以将异步变为同步执行,只不过效率偏低:
es7的await将异步转同步;
juery的ajax设置async:false
2.异步处理(不嵌套):
es6的Promise可以实现:
china().then(jiangshu).then(xian).then(function(data){
    console.log(data)
})
Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
不用es6以上的情况,用jquery也可以:
var d1 = $.ajax();
var d2 = $.ajax();
$.when( d1, d2 ).done(function ( v1, v2 ) {});
3.异步处理(嵌套):
在a接口的成功回调里执行b,在b接口的成功回调里执行c
//promise实现
在Promise的内部,有一个状态管理器的存在,有三种状态:pending、fulfilled、rejected。
(1) promise 对象初始化状态为 pending。
(2) 当调用resolve(成功),会由pending => fulfilled。
(3) 当调用reject(失败),会由pending => rejected。
因此,看上面的的代码中的resolve(num)其实是将promise的状态由pending改为fulfilled,然后向then的成功回掉函数传值,reject反之。但是需要记住的是注意promsie状态 只能由 pending => fulfilled/rejected, 一旦修改就不能再变(记住,一定要记住,下面会考到)。
当状态为fulfilled(rejected反之)时,then的成功回调函数会被调用,并接受上面传来的num,进而进行操作。promise.then方法每次调用,都返回一个新的promise对象 所以可以链式写法(无论resolve还是reject都是这样)。
//promise原理 -- 发布订阅模式
发布者存在一个数组list用于缓存成功的回调(onResolve)和失败的回调(onReject)的函数,等到一定条件下执行emit,订阅的异步函数都会执行。

2. vue生命周期?销毁生命周期里能干那些事?那在销毁生命周期里清除缓存,页面刷新时会执行吗?

我们从destroyed的字面意思可知,中文意为是“销毁”的意思,当我们离开这个页面的时候,便会调用这个函数(具体可以看看vue的的生命周期),我们常用来销毁一些监听事件及定时函数,例如:
// 销毁监听事件
destroyed() {
  clearInterval();
  window.removeEventListener('resize', this.resizeWin)
}
// 页面刷新
在页面刷新时,实例依次执行了beforeCreate(),created(),beforeMount(),mounted(),beforeUpdate(),updated()。并没有来得及执行destroy,与把页面关闭再重新打开的效果是一样的。所以在beforeDestroy或destroyed时执行的代码,要额外考虑一下对页面刷新的处理。

3. vue自定义指令?如何利用自定义指令封装自定义插件?用过哪些自定义插件?

Vue.directive(‘参数名称’,{}) 定义全局指令,它有两个参数
参数1:指令名称,注意在定义的时候,指令名称前不需要加 v- 前缀,但是在调用的时候,必须加v- 前缀。
参数2:参数2是一个对象,这个对象身上有一些指令相关的函数(也就是下边介绍的钩子函数),这些函数可以在特定的阶段,执行相关操作。
例子:
<div>
    <input type="text" v-autoFocus><!-- 让input元素在打开页面的时候就获得焦点 -->
</div>
Vue.directive('autoFcs',{
  // 钩子函数,被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
  inserted(el){
    el.focus()
    console.log( 'inserted' );
  },
  // 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  bind(){
    console.log( 'bind' );
  },
  // 所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。
  // 指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 
  update(){
    console.log( 'update' );
  },
  // 所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
  componentUpdated(){
    console.log( 'componentUpdated' );
  },
  // 只调用一次,指令与元素解绑时调用。
  unbind(){
    console.log( 'unbind' );
  }
})
// 利用自定义指令封装自定义插件

// 常用的自定义插件
1.Vue-ScrollTo:这个指令监听元素的点击事件,然后滚动到指定位置。我通常用来处理文章目录跳转和导航跳转。
npm install --save vue-scrollto
2.Vue-Lazyload:图片懒加载,非常方便。
npm install --save vue-lazyload
3.V-Tooltip
几乎每个项目都会用到 tooltip。这个指令可以给元素添加响应式的tooltip,并可控制显示位置、触发方式和监听事件。
还有一个比较流行的tooltip插件vue-directive-tooltip.
npm install --save v-tooltip
4.V-Scroll-Lock
基于 body-scroll-lock 开发,这个指令的作用是在打开模态浮层的时候防止下层的元素滚动。
npm install --save v-scroll-lock
5.V-Money
安装: npm install --save v-money
如果你需要在输入框里加上货币前缀或后缀、保留小数点位数或者设置小数点符号——不用找了,就是它!一行代码搞定这些需求:
6.Vue-Infinite-Scroll
安装: npm install --save vue-infinite-scroll
无限滚动指令,当滚动到页面底部时会触发绑定的方法。
7.Vue-Clampy
安装: npm install --save @clampy-js/vue-clampy
这个指令会截断元素里的文本,并在末尾加上省略号。它是用clampy.js实现的。
8.Vue-InputMask
安装: npm install --save vue-inputmask
当你需要在输入框里格式化日期时,这个指令会自动生成格式化文本。基于Inputmask library 开发。
9.Vue-Focus
安装: npm install --save vue-focus
有时候,用户在界面里操作,需要让某个输入框获得焦点。这个指令就是干这个的。

4.this.flag = true;this.flag = false;this.flag = true;实际执行几次?nextTick原理?

实际执行俩次:
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0)代替。
nextTick的主要应用的场景及原因;
1.在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中
在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted()钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题 。
2.在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
具体原因在Vue的官方文档中详细解释:
例如,当你设置vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。

5.vue按需加载?vue组件的异步加载?

 

6.echarts怎么自定义改样式?

 

7.如何在ui框架组件上定义的方法里带自己要传的参数?箭头函数原理?箭头函数与普通函数的区别?

elementUI 等 UI框架中,@change方法传递参数
有些业务中,在使用 @change 回调的时候需要动态获取当前循环下的特定值,但是@change方法一旦传递参数就会覆盖原本的数据,对此,有两种方法解决:
// 这种方法据说会改变 this 指向
<el-input-number @change="(value) => numberChange(value, scope.row)" />
// 使用$event
<el-input-number @change="numberChange($event, scope.row, scope.$index) " />
原理和Vue的子组件绑定的方法中传入自定义参数是一样的
区别:
箭头函数没有this,它的this值继承自外围作用域;
普通函数的this指向调用它的那个对象;
箭头函数不可以当做构造函数,也就是说,不可以使用new命令,否则会抛出一个错误;
不可以使用arguments对象,该对象在函数体内不存在,如果要用,可以用rest参数代替;

8.闭包实际用法?

9.深拷贝?原生js如何实现一个深拷贝?

深拷贝:JSON.parse(JSON.stringify(copyObj));
缺点:
1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式;
2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象;
3、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
4、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
// 简单实现一个深拷贝
function cloneDeep2(source) {
    if (!isObject(source)) return source; // 非对象返回自身
    var target = Array.isArray(source) ? [] : {};
    for(var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            if (isObject(source[key])) {
                target[key] = cloneDeep2(source[key]); // 注意这里
            } else {
                target[key] = source[key];
            }
        }
    }
    return target;
}
// 使用上面测试用例测试一下
var b = cloneDeep2(a);
console.log(b);
// { 
//   name: 'muyiy', 
//   book: { title: 'You Don\'t Know JS', price: '45' },
//   a1: undefined,
//   a2: null,
//   a3: 123
// }

10.git指令?

//比如add. 之后我想要撤销之前的选择
使用 git add . 将所有文件添加到库中,不小心将一些不需要加入版本库的文件加到了版本库中。由于此时还没有提交所以不存在HEAD版本,不能使用 git reset HEAD命令。
git rm -r --cached
//不小心使用git pull合并冲突,如果想把当前的修改都放弃,你可以用下面的命令回到合并之前的状态:
git reset --hard HEAD
//查看所有分支
git branch -a
//抓取dev分支
git fetch origin dev:dev
//切换分支
git checkout dev 
//创建dev分支
git checkout -b dev

1.函数的原型,原型链,proto和prototype

2.type of 和 instance of

3.预加载,懒加载的原理,v-lazy,

4.判断大量数据类型,用Object.has。。。。toString

5.轮训循环实现ajax请求,setInterval实现为啥会造成js阻塞

6.微信小程序怎么实现echarts的

7.JS运行机制(宏任务微任务什么的)

8.二分法实现在数组里找其中某个值的位置

 

1.命令行build一个项目?(没想明白。。。不就是npm run build的嘛)

2.uni-app开发h5,小程序,app...

uni-app在2019年底推出了3.0版本,是市面上非常优秀的一款开发混合app的框架,他可以做到一套代码+if条件语法编译生成h5,小程序,app等,当然如果要要玩熟,必须来个全套,需要时间去研究。

3.@RequestBody和@RequestParam区别?

首先我们要明白我们常用的get,post等HTTP请求中,几种常见的Content-Type类型:
一、application/x-www-form-urlencoded
最常见的 POST 提交数据的方式,原生Form表单,如果不设置 enctype 属性,默认为application/x-www-form-urlencoded 方式提交数据。
二、multipart/form-data
另一个常见的 POST 数据提交的方式, Form 表单的 enctype 设置为multipart/form-data
三、application/json
Content-Type: application/json 作为响应头比较常见。
四、text/xml
五、binary (application/octet-stream)
在Chrome浏览器的Postman工具中,还可以看到”binary“这一类型,指的就是一些二进制文件类型。
@RequestParam
接收的参数是来自requestHeader中,即请求头。用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容,Content-Type默认为该属性。@RequestParam也可用于其它类型的请求,例如:POST、DELETE等请求。
@RequestBody
注解@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。
GET请求中,因为没有HttpEntity,所以@RequestBody并不适用。
POST请求中,通过HttpEntity传递的参数,必须要在请求头中声明数据的类型Content-Type,SpringMVC通过使用
//后端解析这俩种有啥不同
@RequestParam
在SpringMVC后台控制层获取参数的方式主要有两种,一种是request.getParameter("name"),另外一种是用注解@RequestParam直接获取。
@RequestBody
@RequestBody是作用在形参列表上,用于将前台发送过来固定格式的数据【xml 格式或者 json等】封装为对应的 JavaBean 对象,封装时使用到的一个对象是系统默认配置的 HttpMessageConverter进行解析,然后封装到形参上。

4.uni-app里强制刷新?

uni-app用的vue.js的核心语法,所以uni-app用这个this.$forceUpdate()

5.linux常用命令?

1、打开tomcat配置文件
#vi /usr/local/apache-tomcat/conf/server.xml
5、 重启tomcat,方法如下:
#/apache-tomcat/bin/./shutdown.sh  【关闭】
#/apache-tomcat/bin/./startup.sh 【打开】

 

//技术二面

1.最近项目中遇到什么问题,及解决方案?

//内存溢出
watch的深度监听deep:true 导致了 Maximum call stack size exceeded
例子:deep:true,深度监听,又在监听的方法里操作数据。。。
解决:监听某一个属性,‘data.key’,deep:false
//全局性的接口请求加遮罩,接口请求完成遮罩去除
在axios的请求拦截器中配置apiNums,请求过来++,响应拦截器中请求完成–;为0 则关闭loading

2.最近有学习什么新技术?平时自己逛什么社区?

uni-app利用vue语法开发h5,微信小程序,android和ios;
腾讯课堂听一些大牛讲座,或者购买学习进阶课程;

3.单页面应用和多页面应用的优缺点?

//单页应用
优点:页面切换快
因为页面每次切换跳转时,并不需要做html文件的请求,这样就减少了http发送
缺点:首屏时间慢,SEO差
因为首屏时需要请求html,同时还要发送js请求,两次请求回来了,首屏才会展示出来。相对于多页应用,首屏时间慢。
SEO效果差,因为搜索引擎只认识html里的内容,不认识js的内容,而单页应用的内容都是靠js渲染生成出来的,搜索引擎不识别这部分内容
//解决
vue项目的seo:
一、ssr
vue-cli+nuxt.js  ssr的原理就是服务器端渲染,然后返回。用nuxt的话,最好是项目刚开始就使用,不然就要重构代码,费时费劲,成本很高,对服务器的压力还是比较大。但是优点是首屏加载速度会比较快。
二、预渲染:prerender-spa-plugin插件
只针对部分页面。如果是详情页,希望seo收录每个详情页的信息,则不太适用。或者项目过大的情况,配置过多,打包会很漫长。

4.vue<keep-alive>

prop:
include: 字符串或正则表达式。只有匹配的组件会被缓存。
exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
//组件
<keep-alive include="test-keep-alive">
    <!-- 将缓存name为test-keep-alive的组件 -->
    <component></component>
</keep-alive>
//结合router,缓存部分页面
<keep-alive>
     <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
//
keep-alive生命周期钩子函数:activated、deactivated
使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。
首次激活时,activated都在mounted后。
再次激活时,本组件只走activated(另外一组件先失活deactivated)
组件失活时,均不走beforeDestroy和destroyed

5.vue懒加载

3种方式:vue异步组件、es6提案的import()、webpack的require.ensure()

new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})
components: {
  AddCustomerSchedule(resolve) {
     require(["../components/AddCustomer"], resolve);
  }
},

6.mvvm的双向绑定原理?

mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

7.谈谈vue和react?

//两者的本质区别
vue - 本质是 MVVM 框架,由 MVC 发展而来
React - 本质是前端组件化框架,由后端组件化发展而来
vue - 使用模板(最初由 angular 提出)
React - 使用 JSX(jsx不是react独有的,已经成了一种标准)
React 本身就是组件化,没有组件化就不是 React
vue 也支持组件化,不过是在 MVVM 上的扩展
//两者共同点
都支持组件化
都是数据驱动视图
//自己的一些看法
模板语法上,我更加倾向于 JSX,因为它更接近js 语法(列如vue的循环用的是新指令v-for,而react用的是js中的map()函数)
模板分离上,我更加倾向于 vue(数据和视图分离的更彻底)
组件化上,我更加倾向于 React ,做的彻底
国内使用,首推 vue 。文档更易读、易学、社区够大 。 如果团队水平较高,推荐使用 React 。组件化和 JSX 大型项目用react,小型项目用Vue

8.数据结构和算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值