2021年前端面试题汇总vue、js、es6
2021-07-14 本文已影响0人
小呆糊总
Vue中computed和watch、method的区别
computed:计算属性只有在相关的数据发生变化时才会改变要计算的属性,当相关数据没有变化是,它会读取缓存。
一个数据受多个数据影响
a.支持缓存,只有依赖数据发生改变,才会重新进行计算
b.不支持异步,当computed内有异步操作时无效,无法监听数据的变化
watch:当需要在数据变化时执行异步或开销较大的操作时,一个数据影响多个数据
a. 不支持缓存,数据变,直接会触发相应的操作;
b.watch支持异步;
methods:每次都会重新计算,computed只有依赖的数据变化时,才重新计算
vue是否可以监听数组与对象的变化
Vue是可以监听数组改变的,只是受JavaScript的限制,以下两种情况除外:
a.当你利用索引直接设置一个数组项时,例如:vm.items[indexofItem]=newValue
b.当你修改数组的长度时,例如:vm.items.length=newLength
vue 无法监听数组变化的解决方案:
1).this.set(arr, index, newVal);
2).使用数组 splice 方法可以监听,例子上面有
3).使用临时变量直接赋值的方式
vue 可以监听直接赋值的对象this.watchObj = {name: 'popo'};
vue 不能监听对象属性的添加、修改、删除
vue 监听对象的解决方法使用 this.$set(object, key, value)
v-show与v-if的区别
v-show 本质就是通过设置 css 中的 display 设置为 none,控制隐藏
v-if 是动态的向 DOM 树内添加或者删除 DOM 元素
v-show 只编译一次,后面其实就是控制 css,而 v-if 不停的销毁和创建,
如果要频繁切换某节点时,使用 v-show
this.$nextTick()
this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新
keep-alive
原理:就是将需要缓存的VNode节点保存在this.cache中/在render时,如果VNode的name符合在缓存条件
(可以用include以及exclude控制),则会从this.cache中取出之前缓存的VNode实例进行渲染。
Vue 的响应式原理:
Vue是采用数据劫持配合发布者-订阅者模式,通过Object.defineProperty来()
来劫持各个属性的getter和setter在数据发生变化的时候,发布消息给依赖收集器,
去通知观察者,做出对应的回调函数去更新视图。
本地实现vue的双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>测试</title>
</head>
<body>
<!-- 本地实现双向绑定 -->
<input type="text" id="input">
<div id="show"></div>
</body>
<script>
// 本地实现双向绑定
var obj={}
function defineProperty(obj,attr){
var val;
Object.defineProperty(obj,attr,{
get:function(){
return val
},
set:function(newVal){
if(newVal === val){
return
}
val = newVal
document.getElementById('input').value = newVal
document.getElementById('show').innerText = newVal
}
})
}
document.getElementById("input").addEventListener('keyup',function(e){
obj.txt = e.target.value
})
defineProperty(obj,'txt')
</script>
</html>
vuex的原理
vuex是利用vue的mixin混入机制,在beforeCreate钩子前混入vuexInit方法
vuexInit方法实现了store注入vue组件实例,并注册了vuex store的引用属性$store
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,
并以相应的规则保证状态以一种可预测的方式发生变化。
Vue中key的作用
key的特殊attribute主要用在Vue的虚拟DOM算法,在新旧Nodes对比时辨识VNodes。
vue的生命周期
(开始创建、初始化数据、编译模板、挂载Dom、渲染、更新、渲染、卸载)主要分为八个阶段:
1.beforeCreate data 和 $el 都没有初始化 全部为 undefined
2.created data 初始化完成,但 $el 没有初始化
3.beforeMount data 和 $el 均已存在,但 DOM 为虚拟DOM 仍未完全加载 eg:{{message}}
4.mounted data 和 $el 均已存在,并且 DOM 加载完成 ,完成挂载
当data中数据发生改变时触发update相关函数
5.beforeUpdate 渲染完成,并监测到data发生变化,在变化的数据重新渲染视图之前会触发,
这也是重新渲染之前最后修改数据的机会
6.updated 监测到data发生变化,并完成渲染更新视图之后触发
6.beforeDestory 实例销毁之前调用 , 实例仍然完全可用。
7.destroyed 实例销毁后调用。
调用后,实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
vue的组件通信有哪些,具体用哪些方法?什么时候用vuex
父子props
兄弟 $emit
子父 $emit事件
祖父/子/孙子 provide/inject
vuex
Vuex与localStorage
vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,
具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,
刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state
hash与history的区别,在使用中遇到了哪些问题
即地址栏 URL 中的 # 符号hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,
因此改变 hash 不会重新加载页面。
hash模式背后的原理是onhashchange事件,可以在window对象上监听这个事件,
因为hash发生变化的url都会被浏览器记录下来,从而你会发现浏览器的前进后退都可以用了
history利用H5的 history中新增的两个API pushState() 和 replaceState() 和一个
事件onpopstate监听URL变化
相对定位与绝对定位;相对定位?flex布局垂直居中?绝对定位与用translate定位有什么区别
1.position 的四个值:static、relative、absolute、fixed。
绝对定位:absolute 和 fixed 统称为绝对定位
相对定位:relative
默认值:static
relative:相对于原来位置移动,元素设置此属性之后仍然处在文档流中,不影响
其他元素的布局
absolute:元素会脱离文档流,如果设置偏移量,会影响其他元素的位置定位
absolute定位原理剖析:
(1.在父元素没有设置相对定位或绝对定位的情况下,元素相对于根元素定位(即html元素)(是父元素没有)。
(2.父元素设置了相对定位或绝对定位,元素会相对于离自己最近的设置了相对或
绝对定位的父元素进行定位(或者说离自己最近的不是static的父元素进行定位,因为元素默认是static)
flex布局垂直居中:
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
事件委托:
事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
transition、transform、animate的区别?
transition需要事件触发,比如:hover、:focus、:checked或者js
操作css样式的变更,所以没法在网页加载时自动发生。
transition是一次性的,不能重复发生,除非一再触发。
transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。
animation不需要触发
可以定义初始中间结束状态
可重复发生
transform: 应用于元素的2D或3D转换。这个属性允许你将元素旋转,缩放,移动,倾斜等。
旋转:rotate()、缩放:scale()、移动:translate()、倾斜:skew()
在浏览器输入url后发生了什么
1.DNS域名解析;
2.建立TCP连接;
3.发送HTTP请求;
4.服务器处理请求;
5.返回响应结果;
6.关闭TCP连接;
7.浏览器解析HTML;
8.浏览器布局渲染;
get、post的区别
1.get传参方式是通过地址栏URL传递,是可以直接看到get传递的参数,post传参方式参数URL不可见,
get把请求的数据在URL后通过?连接,通过&进行参数分割。post将参数存放在HTTP的包体内
2.get传递数据是通过URL进行传递,对传递的数据长度是受到URL大小的限制,
URL最大长度是2048个字符。post没有长度限制
3.get后退不会有影响,post后退会重新进行提交
4.get请求可以被缓存,post不可以被缓存
谈谈你对 TCP 三次握手和四次挥手的理解
http状态码
200请求成功
301永久重定向
302临时重定向
401需要用户身份验证
404资源未找到
500服务器内部错误,无法完成请求
502作为网关或代理服务器请求时,从远程服务器获取到一个无效响应
504充当网关或带理服务器,未及时从远端服务器获取请求
说一下CORS?CORS与JSONP的比较
跨域资源共享它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS
的网站请求数据。
JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面
中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函
数中的JSON数据
说一下宏任务和微任务?
image.pngimage.png
说一下继承的几种方式及优缺点?
1)原型链继承:
问题:引用类型的属性被所有实例共享,一个被修改了,就都修改了
2)借用构造函数继承call或apply
问题:但是只能继承父类的实例属性和方法,不能继承原型属性或者方法
优点:解决了数据共享问题
3)组合继承
问题:子类原型上多了一份父类的实例属性
优点:解决了 原型继承和构造函数继承的缺点
其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
深拷贝和浅拷贝
深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
假设B复制了A,修改A的时候,看B是否发生变化:
如果B跟着也变了,说明是浅拷贝,拿人手短!(修改堆内存中的同一个值)
如果B没有改变,说明是深拷贝,自食其力!(修改堆内存中的不同的值)
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存
数组去重 的方法
1)利用ES6 Set去重(ES6中最常用)
2)利用for嵌套for,然后splice去重(ES5中最常用)
3)利用indexOf去重
4)利用sort()然后判断相邻元素
5)利用hasOwnProperty
6)利用filter
7)利用Map数据结构去重
js中判断是否是对象typeof、instanceof和constructor的区别
(1)typeof运算符,通常会返回:"undefined"、"object"、"boolean"、"number" 、"function" 和 "string"的字符串。数组和对象都返回"object"。
image.png
(2)instanceof运算符用来判断一个对象是否为一个类的实例;判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。可以区分数组和对象。
image.png
(3)constructor返回变量的构造函数;返回对创建此对象的数组函数的引用。可以区分数组和对象。
image.png
JS中的for循环
for
forEach
filter
map
some
every
原型与原型链prototype与proto
原型:
①所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
②所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
③所有引用类型的__proto__属性指向它构造函数的prototype
原型链:
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__
隐式原型上查找,即它的构造函数的prototype,
如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个
链式结构,我们称为原型链。
改变this指向的方法bind,call,apply
function.bind(o,args….)bind返回一个作为方法调用的函数,一个新函数,
该函数会作为o的方法来调用,并向他传入args参数
apply传的参数,第一个是要将this指向谁,第二个是数组参数
call传的参数是多个,第一个是要将this指向谁,其他是参数
call和apply返回的是调用函数function的返回值
闭包,闭包的作用域
闭包就是能够读取其他函数内部变量的函数。
它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,
另一个就是让这些变量的值始终保持在内存中,不会在f1调用后被自动清除。
递归:什么是递归?项目中什么位置用到了递归
['']==''返回什么?为什么?运算符==进行了什么操作?
1.[''].valueof转为原始值''
2.''转为数字0
3.0==''再将''转为数字0,再比较
请求多个接口时,要保证同时拿到数据,渲染到同一个页面上的方法。一个页面渲染需要3个接口返回的数据,怎么判断这3个接口都返回成功
Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
Promise.all([methods1, methods2]).then(res => {
//在方法1 和方法2 都请求成功时再进行操作。
})
es6的新特性
1.let/const的变量声明
2.模板字符串
3.箭头函数
4.参数的默认值赋值
5.对象与数组的解构赋值
6.for of遍历迭代器如数组,for/in遍历对象
es6遍历对象的方法
for … in
Object.keys()
Object.getOwnPropertyNames(obj),
Reflect.ownKeys(obj)
let var const 声明变量的区别
① var声明的变量属于函数作用域;let 和 const 声明的变量属于块级作用域,不能跨函数访问;
② var存在变量提升现象,而 let 和 const 没有;
③ var变量可以重复声明,值可改变;在同一个块级作用域下:let变量不能重新声明;
const定义的变量是常量,声明时必须赋值,但不允许重复赋值,如果定义的是引用类型,可以修改数据内部结构。
柯里化函数:一道经典面试题
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数
var _args = Array.prototype.slice.call(arguments);
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
var _adder = function() {
_args.push(...arguments);
return _adder;
};
// 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = function () {
return _args.reduce(function (a, b) {
return a + b;
});
}
return _adder;
}
add(1)(2)(3) // 6
add(1, 2, 3)(4) // 10
add(1)(2)(3)(4)(5) // 15
add(2, 6)(1) // 9
普通函数与箭头函数的区别
① 外形不同:箭头函数使用箭头定义,普通函数中没有
②箭头函数都是匿名函数普通函数可以有匿名函数,也可以有具体名函数,但是箭头函数都是匿名函数
③箭头函数不能用于构造函数,不能使用new
③箭头函数中this的指向不同
在普通函数中,this总是指向调用它的对象,如果用作构造函数,this指向创建的对象实例。
延长作用域链
try-catch 语句的 catch 块;
with 语句
前端性能优化
1.减少请求数量:
合并:公共库合并
图片处理:雪碧图,base64,字体图标如阿里图标库
减少重定向
使用缓存
不使用CSS @import
避免使用空的src和href
2.减少资源大小
【1.压缩】:
html压缩:不显示 空格,制表符,换行符
css压缩:删除无效代码,语义合并
JS压缩与混乱包括无效字符及注释的删除、代码语义的缩减和优化、降低代
码可读性,实现代码保护
图片压缩
【2.使用webp】:在安卓下可以使用webp格式的图片,它具有更优的图像数据
压缩算法,能带来更小的图片体积
【3.开启Gzip:】HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术
3.优化网络连接:dns预解析
<link rel="dns-prefecth" href="https://www.google.com">
4.优化资源加载:
【加载位置】,css在head,js在body最后,
【资源加载时机】:
1、异步script标签:defer、async
2、模块按需加载:需要根据路由来加载当前页面需要的业务模块
3、使用资源预加载preload和资源预读取prefetch
4、资源懒加载与资源预加载
5.减少重绘回流:
【样式设置】:
1、避免使用层级较深的选择器
2、避免使用CSS表达式
3、不要使用table布局
4、能够使用CSS实现的效果,尽量使用CSS而不使用JS实现
【DOM优化】:
1、缓存DOM
2、减少DOM深度及DOM数量
3、事件代理
4、防抖和节流
5、及时清理环境:垃圾收集(标记清除,引用计数)
6.webpack优化
【打包公共代码】
【动态导入和按需加载】
【剔除无用代码】
【长缓存优化】
【公用代码内联】:使用html-webpack-inline-chunk-plugin插件将mainfest.js内联到html文件中
promise的三种状态
pending/reslove/reject 。pending就是未完成,resolve可以理解为成功,reject可以理解为拒绝
函数与变量的提升
变量提升:在函数域里定义一个和外部变量一样名称的变量时,变量的声明会提升至第一句,赋值则不会变。
函数提升:在写JS代码的时候,有两种写法,一种是函数表达式,
另外一种是函数声明方式。我们需要重点注意的是,只有函数声明形式才能被提升。
防抖节流
作用域与作用域链
异步控制(promise,es6 generate,Async)
模块化开发模式(AMD,CMD,KMD)
javascript解释器(异步I/O实现,垃圾回收,事件队列)
自身的优点
以后的打算
离职的原因
技术面试问到你还有什么要问的吗
未来一年,部门的工作任务是什么
入职后的3个月,会参加哪些培训,
团队有多少人,工作年限是多少
可以大概讲一下公司的企业文化吗