1.js中的类数组有哪些,如何转换为真数组?
类数组:nodeList HTMLCollection arguments
转换:扩展运算符,Array.from(),Array.prototype.slice.apply()
2.封装一个dialog组件
3.npm run dev流程
在npm run dev的时候,首先会去项目的package.json文件里找scripts 里找对应的 dev ,然后执行 dev 的命令。
4.vue 加载流程
5.垂直水平居中的方式
第一种:定位+transform
.work {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
第二种:使用绝对定位 + margin: auto,给子元素添加如下样式
.work2 {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin:auto;
}
第三种:弹性盒子
.par-work {
height: 100vh;
display:flex;
justify-content:center;
align-items:center;
}
第四种:grid布局
.par-work3 {
display: grid;
height: 500px;
}
.son-work3 {
align-self: center; /*设置单元格内容的垂直位置*/
justify-self: center; /*设置单元格内容的水平位置*/
}
6.JS中的this指向
普通函数:关于this,谁调用就指向谁,没有调用者,就指向全局对象window。
箭头函数:箭头函数的this指向于函数作用域所用的对象。
如果单独使用,this 表示全局对象。
在事件中,this 表示接收事件的元素。
构造函数中,this指向实例。
7.let const var区别
let const 不能重复声明,不存在变量提升,存在暂时性死区,块级作用域,var声明的变量挂载在window上。
8.vue双向数据绑定原理
vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。
9.vue组件传值的方式
父->子 自定义属性
子->父 自定义方法
vuex
provide inject
$ref
$parent
$children
10.什么是虚拟DOM
虚拟DOM本质就是用树型结构的JS对象来描述真实的DOM结构的信息,这个树结构的JS对象包含了整个DOM结构的信息.
11.列表渲染中key的作用
在渲染成新的真实dom前,会执行diff算法,将新的虚拟dom和旧的虚拟dom,根据key来进行对比
12.apply call bind的区别
call和apply是改变后页面加载之后就立即执行,是同步代码。
call和bind的参数逐一传入,apply的参数放在数组中。
bind是异步代码,改变后不会立即执行;而是返回一个新的函数。
13.promise的三个状态
pending reject resolve
14.父子组件的生命周期执行顺序
父beforeCreate->父created->->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父beforeMount->父mounted
销毁阶段
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
15.箭头函数和普通函数的区别
16.判断数据类型的方法
1.typeof
缺点:用typeof检测构造函数创建的Number,String,Boolean都返回object,检测数组和对象也都返回object
2.instranceof
缺点:Number,String,Boolean字面量方式的数据无法使用instanceof准确判断
例如:
let str="abc"
console.log(str instanceof String) //false
3.constructor
缺点:如果输出一个类型的实例的constructor返回不可见的底层代码
4.Object.prototype.toString.call()
var toString = Object.prototype.toString;
toString.call(123); //"[object Number]"
17.移动端设置0.5像素的边框
伪类结合transform:scale(0.5)
.box::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
border-radius: 8px;
border: 1px solid royalblue;
transform: scale(0.5);
transform-origin: 0 0;
pointer-events: none;
}
18.性能优化
1.体积优化
静态资源(图片,字体,图标等)压缩,JS、CSS压缩,TreeShaking去除多余代码,第三方库按需引入
2.传输优化
路由懒加载,gzip压缩,缩小TCP传输时js、css文件的体积,cdn托管
3.用户体验优化
设置加载动画,骨架屏等视觉等待效果,图片懒加载
19.vuex持久化存储
使用persistedState插件或存储到本地存储中
20.Object.freeze()函数的作用
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
21.keep-alive的作用
在开发中经常有从列表跳到详情页,然后返回详情页的时候需要缓存列表页的原来数据以及滚动位置,这个时候就需要保存状态,要缓存状态。
22.computed和watch的区别
computed支持缓存,相依赖的数据发生改变才会重新计算;watch不支持缓存,只要监听的数据变化就会触发相应操作
computed不支持异步,当computed内有异步操作时是无法监听数据变化的;watch支持异步操作
computed属性的属性值是一函数,函数返回值为属性的属性值,computed中每个属性都可以设置set与get方法。watch监听的数据必须是data中声明过或父组件传递过来的props中的数据,当数据变化时,触发监听器
23.$route和$router的区别
$router是用来操作路由,$route是用来获取路由信息
24.vue中的插槽
单插槽
具名插槽
v-slot:name可以缩写成#name
作用域插槽
作用域插槽允许我们在使用插槽时传递数据。
25.vue中data数据可以用$,_命名吗?
名字以_和data._property访问
26.JS垃圾回收机制
引用计数和标记清除
引用计数:内部通过引用计数器,来维护当前对象的引用数,从而判断该对象的引用数是否为0,来决定它是否是一个垃圾对象。如果引用数值为0,GC就开始工作,将其所在的内存空间进行回收释放和再使用
标记清除:
标记:从根节点遍历为每个可以访问到的对象都打上一个标记,表示该对象可达。
清除:在没有可用分块时,对堆内存遍历,若没有被标记为可达对象就将其回收。
27.前端常用设计模式
工厂模式,观察者模式,发布订阅模式,单例模式
28.new关键字的作用
1.创建空对象
2.改变this指向空对象
3.改变对象的proto为构造函数原型
4.隐式返回这个对象
29.数组方法有哪些?哪些能改变原数组
indexOf 、lastIndexOf 、every 、some 、filter 、map 、concat 、slice不能改变原数组
push、pop、shift、unshift、reverse、sort、splice会改变原数组
30.节流防抖
防抖:多次触发,只执行最后一次
function debounce(fn, delay){
let timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(()=> {
fn.apply(this, arguments);
}, delay)
}
}
节流:规定时间内只触发一次。
function throttle(fn, delay){
let valid = true;
return function(){
if(valid) { //如果阀门已经打开,就继续往下
setTimeout(()=> {
fn.apply(this, arguments);//定时器结束后执行
valid = true;//执行完成后打开阀门
}, delay)
valid = false;//关闭阀门
}
}
}
31.事件循环机制
同步任务->微任务->宏任务
32.前端跨域
jsonp,document.domain + iframe,window.name + iframe, postMessage,CORS, nginx代理
33.深拷贝,浅拷贝
深拷贝:
1.递归
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
2.JSON.stringify()
function deepClone(obj){
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
34.
下面分别使用 JSON.stringify 方法,返回值 res 分别是
const fn = function(){}
const res = JSON.stringify(fn)
const num = 123
const res = JSON.stringify(num)
const res = JSON.stringify(NaN)
const b = true
const res = JSON.stringify(b)
A. 'function'、'123'、'NaN'、'true'
B. undefined、'123'、undefined、'true'
C. undefined、'123'、'null'、'true'
D. undefined、'123'、'null'、undefined
答案:C
35.关于将 Promise.all 和 Promise.race 传入空数组的两段代码的输出结果说法正确的是:
Promise.all([]).then((res) => {
console.log('all');
});
Promise.race([]).then((res) => {
console.log('race');
});
A. all 和 race 都会被输出
B. all 和 race 都不会被输出
C. all 会被输出,而 race 不会被输出
D. all 不会被输出,race 会被输出
答案:C
36.下列结果返回 true 的是
A. null == undefined
B. null === undefined
C. null === null
D. NaN == null
E. NaN === NaN
F. Infinity + 1 !== Infinity
答案:AC
37 isNaN()原理
38 强缓存与协商缓存
强缓存:浏览器第一次请求某个资源时,如果浏览器希望该用户一段时间内不要再通过服务器请求此资源,直接从浏览器缓存中获取,可在请求头中通过cache-control设置max-age缓存时间,状态码200后面会标明(from disk cache),还可以使用expires设置,但是这个设置方法是通过客户端的时间设置的,而客户端的时间可以修改,所以这个方法有不足之处。
协商缓存:浏览器初次请求资源,服务器返回资源,同时生成一个Etag字段存放在响应头中,浏览器再次请求资源是会在请求头中携带if-none-match字段,值为上次Etag值,用该值与新的Etag值对比,如果相同,则返回状态码304,从缓存中拿该资源;如果不同,则返回200和最新的资源给浏览器。同时Http1.0中使用last-modified属性,表示上次修改时间,对应浏览器请求头为if-modified-since,此值是时间值,但是有时修改事件发生变化不代表数据发生了修改,所以这种方法不准确。
39.Hybird开发中遇到过那些问题,如何解决
(1)position:fixed在ios中滑动闪动的问题
解决方案:不修改top值,使用transform
(2)rem适配安卓border-radius:50%不是圆形
解决方案:安卓会识别1px以下的值,扩大2倍在用scale缩小
(3)iOS底部最后一个元素的margin-bottom失效
解决方案:改成padding-bottom
(4)input的placeholder垂直不居中
解决方案:添加line-height:normal
40.上万条数据不做分页的情况下,如何优化
使用虚拟列表,也就是说在展示的列表上下同时添加虚拟列表,每次滚动时只显示指定几条数据
41.防止用户重复提交
UI层面:disabled按钮或添加全屏的loading
逻辑层:防抖 节流
一般推荐UI层面解决
42.不使用第三方变量交换变量
1 解构赋值
2 加法
let a=1,b=2
a=a+b
b=a-b
a=a-b