一、HTML
1、什么是盒模型,盒模型包括哪些?
盒模型就是把html里面的元素看做是矩形的框,类似于一个盒子的模型。
标准盒模型:width+padding+border+margin
怪异盒模型:width+margin
怪异盒模型就是把padding和border包括在width里面,平时经常使用的box-sizing:boder-box;就是把标准盒模型变成怪异盒模型。
2、怪异盒模型和普通盒模型有哪些区别?
标准盒模型: content-box
怪异盒模型: border-box
二、CSS
1、css的定位有哪几种,分别什么作用
static:静态定位 relative相对元素本身的定位 absolute相对父元素的绝对定位,脱离文本流 fixed相对可视窗的固定定位。
2、垂直居中水平居中等有哪些解决方案(侧面考验对块级元素、行内元素、行内块级元素的了解)
3、动画和过度的熟练度
动画:animation @keyframes
过度:transition
三、JS(包括ES6)****(****函数递归****)
1、什么是基本数据类型和****引用****数据类型?
基本数据类型:保存在栈中的大小确定的值
引用数据类型:就是堆中的一个对象,他的变量是保存在栈中的一个引用地址,通过引用地址可以快速找到堆中的对象。
2、赋值、浅拷贝、深拷贝的区别,并且分别有哪些方法?
> **赋值:**基本类型数据直接在栈中简单赋值,两个独立不影响。引用类型直接拷贝内存地址。
> **浅拷贝: **遍历引用类型中的每一个属性,并且将其基本类型的值的指针进行拷贝,如果遇到复杂类型的值,直接拷贝内存地址。
** 深拷贝:**完全独立的拷贝出新的一块内存地址,两个变量互不干涉,互不影响。
深拷贝的方法:(循环遍历,递归遍历)
3、原型的理解
> **原型(原型对象):**就是一个对象,prototype就是一个原型对象,在每一个函数里面都存在的一个对象。
>** 对象原型:**每个对象都有一个原型_ _proto_ _,是这个对象的原型,他指向的是他的构造函数的原型对象prototype
** 构造函数(coustructor):**原型对象(prototype)对象原型(_ proto _)里面都有这个属性,他指向的是构造函数的本身。
** 原型作用:**共享方法。构造函数中所有的方法都可以定义在原型对象中,所有的实例都可以共享这个方法,实例化对象的时候就不需要单独的开辟一块内存空间了,提高性能,也节省了内存。
** 原型链:**当访问一个对象属性的时候,会先从这个对象本身属性上去查找,没找到,则会去他的proto的原型上去查找,如果没找到再在构造函数的Prototype的原型原型上去查找,知道查找到null为止。这样一层层上去就形成了一个链式结构。
> prototype是构造函数才有的属性,_ _proto_ _每个对象都有的属性
4、闭包
> **能获取函数内部变量的函****数****(声明在函数内部的函数)**
闭包优点:1、防止外界变量污染 2、读取函数内部变量 3、使变量一直保存在内存中。
闭包优点:1、会造成内存溢出(内存泄漏)
let add = null
function a() {
let num =1;
add = () => { num+=1 }
//下面这个就是闭包
return () => {
console.log( num )
}
}
//执行以下代码输出:
const res= a()
res() //1
add() //变量+1了,并且一直保存在内存中
res() //2
5、本地存储
localStorage: 一直存储在本地,一直存在
sessionStorage:页面关闭,存储消失
6、变量提升****(****js预加载技术****)
7、变量作用域****(****全局作用域、局部作用域、块级作用域****)
8、call、apply、bind的作用和用法,利用call(),apply()实现继承
call、apply、bind作用是改变对象的执行上下文(改变this的指向)。
call,apply是立即执行的,bind是返回一个函数,在需要使用的时候再调用。
const student = {name:'lili',age:12}
function s(a,b) {
console.log(a+b)
}
//call直接执行,参数用,分隔。并输出结果3
s.call(student,1,2)
//apply直接执行,参数以数组的形式传递。并输出结果3
s.apply(student,[1,2])
//bind不执行,作用只是改变this的指向
s.bind(student)
9、继承
(1)原型继承,实例共用原型链,属性为引用类型,则会互相影响。
Child.prototype= new Parsent()
(2)构造函数继承,无法继承原型上的属性和方法。
Parsent.call(this)
(3)组合式继承 结合
Parsent.call(this)
Child.prototype= new Parsent()
Child.prototype.constructor = Child
10、this的指向问题
当在全局作用于中,this指向window
普通函数作用域下:非严格模式,指向window ,严格模式undefined
在构造函数中,this指向此构造实例对象,
在对象方法中,this指向该对象
> 箭头函数更改了this的指向,指向词法作用域的外层。
11、异步请求:promise\async await \callback
12、数组用typeof判断出来的类型是什么,哪些方法可以判断是数组?
undefined, boolean,string,number,object,function
Array.isArray(arr) / arr instanceof Array
13、setTimeOut / Promise.resolve().then的执行顺序,宏任务和微任务知识点
/**
* 宏任务:setTimeOut, setInterval, setImmediate, I/O
* 微任务:Promise.resolve(), process.nextTick,promise.resolve().then()
* */
14、Boolean类型的强制转换,
例:let a = [], b = {}, c = 0 ;
写出输出值: console.log(a && b) ; console.log(a && c); console.log(a && b && c) ; console.log(!a && c) ; console.log(a && !c)
15、判断是否为一个数组类型的方法(两种法法)
例: let arr = [1,2,3,4]
利用原型判断,判断这个变量的原型链是否是数组对象: arr instanceof Array //true
Object.prototype.toString.call(arr) 准确判断任何类型
3)利用es6新增的内置对象的方法:Array.isArray(arr) //true
16、什么是事件流?事件流分哪几个阶段?
> 事件流指的是:事件传播的过程.(冒泡、捕获)
(1)事件捕获阶段(2) 处于目标阶段 (3)事件冒泡阶段
**17、熟悉使用Element.addElementListener('事件',‘函数’,true/false) **
最后的ture/false,什么意思?有什么作用?
true 事件按照事件捕获的方式执行, false 事件按照事件冒泡的方式执行
18、'use strict'严格模式,必须写在第一行吗?回答使用'use strict'的优缺点?
是的、但是如果上面是注释的代码,也算是写在最上面,如果没写在最上面,
那么'use strict'会失效。
19、async/await作用
1、await作为求值关键字(后面可以跟promise或表达式),可以直接获取promise的值和表达式的值
2、将异步代码操作变为同步代码的写法。
20、window.onLoad 和$(document).ready()的区别
window.onLoad是数据资源全部加载完毕才执行,ready是dom渲染完毕就执行。
21、作用域和上下文:
作用域:可访问的变量的范围、区域。
上下文:同一个作用域中的变量
22、jsonp的跨域原理:
浏览器是有同源策略限制的,但是src属性不被同源策略限制,所以利用动态插入script标签并且设置src属性,就解决了跨域问题。
23、instanceof原理
instanceof 是判断右边的变量原型prototype是不是在左边的变量的原型链上。
结果为true :
Object instanceof Object / Function instanceof Object / Object instance Function
24、垃圾回收机制,和避免内存泄漏:
当执行遇到函数的时候,会创建一个函数执行上下文,并添加到调用堆栈的栈顶,函数的作用域中包含了函数中声明的所有的变量,当函数执行完毕,对应的执行上下文从栈顶弹出,函数的作用域随之销毁,函数中包含的所有声明的变量统一释放并自动回收。
垃圾回收:就是不定期寻找不再使用的变量,释放并回收内存。
垃圾:就是不再使用的变量或者未被引用的对象。
怎么实现垃圾回收:利用标记-清除法,进行垃圾回收。
1、少创建全局变量
2、手动清除定时器
3、少用闭包
4、清除dom的引用
25、函数柯里化
定义:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
fun(1,2,4)===》 fun(1)(2)(4)
作用:延迟执行、参数复用、提前确认(利用自执行函数,提前确认走那个方向。然后返回一个函数)。
26、new操作符的作用,并写一个js方法实现new运算符
[图片上传失败...(image-dc15e4-1631860993689)]
function ObjectNew() {
//创建一个实例对象对象
let obj = {}
//取得方法的第一个参数为构造函数
const Constructor = [].shift.apply(arguments)
//将该对象的原型指向构造函数的原型对象
obj.__proto__ = Constructor.prototype
//更改构造函数的this指向实例对象,并取得返回值
const res = Constructor.apply(obj, arguments)
//如果有返回对象,就返回对象,没有就返回实例对象
return typeof res === 'object' ? res : obj
}
27、js事件循环机制(Event Loop)
(单线程非阻塞,主线程、执行栈、事件队列)
js是单线程非阻塞的,js只有一个主线程来处理所有的任务,因为js是单线程的,js同一时间只能执行一个方法,这些方法依次排列在执行栈中被依次执行,当方法被执行完毕的时候。js会退出执行环境并且销毁执行环境。当遇到异步事件时,会将这个异步事件挂起,继续执行执行栈中的其他任务,异步事件返回结果后,会将事件添加到事件队列中,等待执行栈中的所有任务执行完毕之后,主线程会去查找事件队列中是否有任务,如果有,主线程会将事件队列中的回调放入执行栈中并依次执行。这样事件就形成了一个循环,叫做事件循环。
28、前端跨页面通信有哪些方法
同源下的页面之间:
1、利用事件监听document.addElementListener(‘click’,fun,false)
2、window.postMessage()
3、h5的本地存储localStorage
非同源下的页面之间
1、JSONP
2、iframe
29、重排和重绘(尽量减少重排重绘)
重排(回流):重新生成布局,重新排列元素
重绘:某些元素的外观被改变,比如color变化。
重绘不一定导致重排,重排一定导致重绘。
30、前端性能优化
(1)外部引入css,script,并且将script放在body的最后。
(2)减少重排重绘
(3)减少去除多余代码,减小代码量
31、浏览器渲染页面的流程:
(1)输入网址,DNS查询,将域名解析为ip
(2)浏览器和服务器建立tcp或者udp连接
(3)浏览器给服务器发送http请求
(4)服务器处理响应请求
(5)服务器返回一个html响应
(6)客户端渲染html
32、模块化
什么是模块化:
(1)将复杂的程序依据一定的规范封装成几个模块,并组合在一起。
(2)块的内部数据与实现是私有的,只是简单向外部暴露一些接口与外部其他模块通信。
模块化方式:
(1)函数模块
(2)对象模块
(3)IIFE(闭包)
模块化的优点:
(1)避免变量命名冲突
(2)更好的分离,按需引入加载
(3)更高的复用性
(4)更高的维护性
33、promise原理
prmise有三种状态:等待pending、成功fulfilled、拒绝rejected。promise一旦改变状态就是不可逆的,当变成fulfilled状态,会立即执行回调函数,回调函数返回的结果被当做参数闯入函数被使用。
四、VUE
1、vue全家桶,分别什么作用?
> vue-cli脚手架:快速搭建vue开发环境,继承资源加载,打包、热更新等一体的vue开发工具。
> vue -router: vue的路由插件,有两种模式hash模式和history模式。
> vuex:状态管理模式,集中式存储管理所有组件的状态,并以相应的规则保证可预测的发生变化。
> axios: 基于promise的http库,实现数据的交互。
>vue的第三方框架,例如element-ui , mint-ui
2、vuex模块
vuex是针对vue.js创建的状态管理仓库。分为state,getter,mutation,action,module五个模块部分,
> state:存储view视图的公共数据
> getters: 计算变量,跟vue中的computed数据相似,具有缓存功能,只有依赖的数据源发生变化,才被重新计算。
> mutations: 提交state数据源状态的唯一方法,只操作同步操作。
> actions: 异步方法请求的地方,通过dispatch触发。能通过commit触发mutations方法。
> modules: store分割的子模块
3、什么是MVVM模式,怎么实现数据双向绑定,数据双向绑定的原理?
model数据交互层逻辑, view视图层展示页面, viewModel中间传送带,是model和view交互的中间键。
采用数据劫持结合发布订阅者模式来改变view层数据。通过Object.defineProperty()中的get,set劫持数据的变化,发布消息给订阅者watcher,触发响应的监听回调更新视图。
通过监听input、change事件赋值改变model层数据
> model变化view视图更新:在vue创建实例的时候,会遍历data中的属性,并通过Object.defineProperty()方法,设置属性的setter/getter,听属性值的变化,当监听到属性值的变化,触发dep.notify()通知订通过observe监阅者,执行watcher.update()方法,执行compile中的回调,改变DOM中的值。
> view视图更新model数据变化:通过文本输入框的change/input事件,获取dom中value值,改变model层数据。
vue2.x:利用object.defineproperty()劫持数据,但是object.defineproperty()不能监听数组的变化,数组中的push,shift等方法无法触发set,vue是通过重写数组这些方法实现数据的劫持。并且要手动递归遍历深层次的对象属性
vue3.0:利用proxy劫持数据,proxy针对的是整个对象,所以对象里面的属性变化,都可以劫持到。能监听到数组的变化,不需要重写数组的方法。嵌套对象需要递归调用proxy。
4、vue中数组和对象是怎么渲染的?
> vue实例初始化之前就在data对象里面定义好的的属性,类型可以是Object、Array、String、Number等各种类型的数据,这样能监听到data里面属性的变化,而重新渲染页面数据,没在data中定义的属性,无法坚监听到数据的变化,可以使用this.$set()方法为属性添加监听事件。
其中Array类型直接改变数组长度 或 利用下标改变数组无法监听到变化,所以页面无法重新渲染。
Object类型:利用delete删除对象某一属性 或 为对象添加某一属性,则无法监听到数据变化。
5、vue-router的两种模式
> hash模式:vue默认使用hash模式,并且如果浏览器不支持history模式的情况,会重新定向为使用hash模式。从#之后的一串数据都属于hash值。改变hash值会触发hashChange事件,然后通过hash值去查找相应的路由,改变视图。使用以下两种方法改变页面内容和浏览器浏览记录:
hashHistory.push() / hashHistory.replace()
history模式:是HTML5中的新增的两个API history.pushState() / history.replaceSate(),能够改变url地址且不会发送请求,可以改变浏览器历史记录栈。需要后端配合使用。
history 致命的缺点就是当改变页面地址后,强制刷新浏览器时,(如果后端没有做准备的话)会报错,因为刷新是拿当前地址去请求服务器的,如果服务器中没有相应的响应,会出现 404 页面。
6、vue2.0和vue3.0的不同,vue3.0有哪些优化?
vue2.x:页面载入时,不管是不是可区域渲染的数据,都会创建监听观察者,所以在页面载入时的性能较低,较慢。
vue3.0:页面是需要用到什么引入什么,不会有冗余的和多余的数据,只有在可见区域中才会为数据创建观察者,初始载入时性能好。
| vue2.x | vuee3.0 |
| 采用Object.defineProperty()进行数据劫持|采用proxy进行数据劫持|
|页面载入时,为data里面的所有数据创建观察者,性能低|页面载入时,只有可见区域的变量创建观察者|
|利用vue.set()为对象添加属性时,这个对象的所有watcher会重新运行|
利用vue.set()为对象添加属性时,只有依赖那个属性的watcher才会重新运行
|
|this指向当前组件|取消了this关键之,直接使用setup携带的参数|
7、vue的生命周期钩子
> beforeCreate 实例初始化之后,数据观测(data observer)和event/watcher 事件配置可以调用
> created 实例创建完成后被立即调用,但是实例还没挂载,不可获取dom
> beforeMount 实例挂载之前调用 ,相关的render函数首次被调用。 (服务器渲染期间不被调用)
> mounted 实例挂载后调用,但是不能保证能获取子组件的dom。使用$nextTick()则能获取整个视图dom
> beforeUpdate 数据更新时调用,dom更新之前
> updated 发生在dom更新之后调用。
> activated 被keep-alive缓存组件激活时调用
> deactivated 被keep-alive缓存组件停用时调用
> beforeDestroy 实例销毁之前调用,仍然可以获取到实例dom
> destroyed 实例销毁之后调用
> errorCaptured 捕获一个来自子孙组件的错误时被调用
8、父子组件的生命周期的顺序
> 父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted ->父mounted
->父beforeUpdate -> 子beforeUpdate ->子updated -> 父updated
-> 父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
9、解释vue的单页面应用
单页面应用指,在vue初始化页面的时候只请求一次资源,之后的页面交互,数据交互都是通过router和ajax来完成,页面并没有刷新。
10、数据的响应式
> 数据分为普通数据类型和引用数据类型(数组、对象),在实例data定义过的property ,都会将其转化为 getter/setter,让其响应数据变化。
(1)普通数据类型
改变数据,直接响应变化
(2)数组
响应式的:push(),split(),slice()等方法、this.$set()方法
非响应式:利用数组下标(arr[0].name)、修改数组长度( arr.length=2)
(3)对象
响应式的:直接赋值(this.obj = {})、this.$set()方法、直接属性赋值存在的属(this.obj.name = '11')
非响应式:对象不存在的属性名赋值(obj.name ='a')、删除某一属性(delete obj.name)
11、vue-router有哪几种导航钩子
(1)全局导航钩子
router.beforeEach(to,form,next)//路由跳转前判断
router.afterEach((to,from)=>{ });// 跳转后判断
(2)组件内的钩子
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是依然渲染该组件是调用
},
beforeRouteLeave(to, from ,next) {
// 导航离开该组件的对应路由时被调用
}
(3)单独路由独享组件:是在路由配置上直接定义
const router = newVueRouter({
routes:[{
path:'/file',
component:File,
beforeEnter:(to,from,next)=>{/*路由钩子*/}
}]
});
12、描述下虚拟DOM
虚拟dom就是一个js对象,用来描述希望在屏幕上看到的内容,能都实现高效更新真实dom。
13、描述数据变化,dom怎么更新
在第一次渲染页面时就创建一份虚拟dom,当数据变化,利用diff算法对比两个虚拟dom的不同,更新不同处。
14、router和route的区别
route:是当前路由的信息,能获取路由和参数
router:是全局路由(VueRouter)实例对象,可以进行路由跳转
15、vue.use()原理
vue.use()是注册使用全局组件,首先回去判断组件有无被注册过,不会重复注册组件。并且可接受的参数类型为对象或者函数。如果是对象,则包含install方法,去调用install方法,install方法的第一个参数为Vue.如果是函数,则直接执行函数,函数接收的第一个参数也是Vue。
16、vue-loader是什么,什么作用?
处理特定语言块。
vue-loader是一个webpack的loader能够处理.vue结尾的单文件页面。
17、非父子组件之间的数据传递:
1、使用vuex数据管理仓库
2、new一个新的vue实例,作为中央事件总线,然后使用on进行数据的传递和接收。
18、v-for为什么要添加key
vue 在更新渲染dom的时候是根据新旧dom进行对比,用key标识每一个节点,使diff算法比较虚拟dom的时候更准确。
19、computed原理:
内部通过dirty属性判断是否从新计算赋值,初始化时dirty设置成true,会读取data中的依赖变量值进行赋值操作。赋值完毕将dirty设置成false,只有当依赖的data变量发生变化时,才会将dirty赋值为true,重新计算值。
20、vue.nextTick()原理
因为DOM更新是异步执行的,DOM更新会加入到任务队列中.先执行完同步代码,再进行DOM的异步更新,所以需要nextTick()的回调是在dom更新之后的任务队列中执行。nextTick的原理是使用promise、mutationObserver、setImmediate、setTimeout顺序来使用。
21、数组哪些方法能被监听到,怎么实现改变dom的?
vue 内部对数组的push、unshift、pop、shift、reverse、sort、splice等七个方法进行拦截,如果数组变化,就通知订阅者更新视图。
22、keep-alive原理和使用
获取keep-alive包裹的组件和组件名,判断组件名是否包含在include中,通过key值查找该组件是否被缓存过,被缓存过,直接获取cache中缓存的vnode,并且更新key值顺序。没被缓存过,则直接返回组件实例,并添加缓存的key值。之后检查被缓存的组件实例是否超出max,超出了,直接删除最原始的缓存数据。
23、为什么组件里面的data必须是函数?
因为每一个vue组件就是一个vue实例,通过new Vue()来实例化,如果data定义为一个对象,就相当于原型中定义一个对象,实例化对象的时候,那么此对象指向同一地址。那么组件复用的时候data都是指向同一个内存地址,改变其一,牵动其二,组件相互影响。如果使用函数,复用组件的时候,每个组件都有各自的data作用域,互相独立。
24、** vm.$set(target,key,val)方法的原理 **
使用这个方法可以给响应式数据添加和更改响应式数据。
首先会判断目标对象时数组还是对象,如果是数组使用splice()方法,替换更改数组。如果是对象,并且添加的属性已存在,则直接赋值,如果对象不存在此属性,先判断此对象是否是响应式变量,如果不是,直接添加键值对,如果是响应式,通过defineReactive()方法进行响应式处理。
五、网络请求
1、http和https的区别
http:安全性低
https:通过加密协议处理过,更安全
2、get和post请求
get:数据通过url传递,直接可见,数据长度受限。
post:数据通过params传递,安全性能更高,能接受的数据容量也更大。
3、http的状态码有哪些,分别代表什么意思
200成功,401需要验证身份,403服务器拒绝请求,404找不到资源,500服务器出错,503服务器不可用。
六、vue3
** 1、vue3有哪些新特性 **
(1)framents(支持多个根节点)
(2)teleport(通过<teleport>标签包裹的元素可插入到任意的元素中,to中可以是id,也可以是class)
(3)composition Api (组合式api)更容易维护代码。
** 2、vue3有哪些方面的提升**
(1)diff算法方面的提升,增加了静态标记
一些非静态的节点会增加一个flag标记,在发生变化的时候,有flag标记的地方才会进行diff算法进行比较。
(2)静态提升
对不参与更新的DOM元素,做今天提升,元素节点只会被创建一次,在渲染时直接复用,节省了在运行时的内存占用。也不会进行diff算法。
(3)体积减小了,采用组合式api,按需引入。
(4)使用proxy进行响应式数据xie