1.怎么定义 Vue-Router 的动态路由?怎么获取传过来的动态参数?
Vue-router中定义动态路由方式有两种:
(1)params类型
1.配置方式:/router/:id
2.传递方式:在path后面跟上对应的值
3.获取方式:this.$route.params.参数名
// 动态路由params
在vue文件中
<router-link :to="'/user/'+id" replace>用户页</router-link>
在index.js
{
path:"/user/:id",
component:User,
}
跳转方式:
// 方法1:
<router-link :to="{ name: 'user', params: { uname: '老曹' }}">按钮</router-link>
// 方法2:
this.$router.push({name:'user',params:{uname:'老曹'}})
// 方法3:
this.$router.push('/user/' + '老曹')
(2)query类型
1.配置方式:无需特别配置
2.传递方式:在配置对象中使用query的key作为传递方式
3.获取方式:this.$route.query.参数名
跳转方式:
// 方法1:
<router-link :to="{ name: 'user', query: { username: '老曹' }}">按钮</router-link>
// 方法2:
this.$router.push({ name: 'user', query:{ username:'老曹' }})
// 方法3:
<router-link :to="{ path: '/user', query: { username:'老曹' }}">按钮</router-link>
// 方法4:
this.$router.push({ path: '/user', query:{ username:'老曹' }})
// 方法5:
this.$router.push('/user?username=' + '老曹')
2.vue和react的区别和优缺点
React是由meta(原facebook)创建的JavaScript UI框架,它推广了Virtual DOM(虚拟DOM)并创造了新的语法——JSX,JSX允许开发者在JavaScript中书写HTML.
Vue是尤雨溪个人开发的框架,它采用的是模板系统,因为模板用的就是普通的HTML,所以使用Vue对现有应用的升级更加容易,而不需要整体重构.
区别:
(1)
- React的思路是All in JS,通过 JavaScript 来生成 HTML,所以设计了 JSX 语法,还有通过 JS 来操作 CSS,社区的styled-component、JSS等。
- Vue是把 HTML,CSS,JavaScript 组合到一起,用各自的处理方式,因为Vue 有单文件组件,可以把 HTML、CSS、JS 写到一个文件中,HTML 提供了模板引擎来处理。 (2)
- React 整体是函数式的思想,在 React 中是单向数据流,推崇结合 immutable 来实现数据不可变。
- Vue 的思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立 Watcher 来监听,当属性变化的时候,响应式的更新对应的虚拟 DOM。 (3)
- react中都是通过import导入相应组件,然后模版中引用;
- Vue组件可以分为全局注册和局部注册 (4)
- Vue有指令系统,让模版可以实现更丰富的功能;
- React只能使用JSX语法 (5)
- Vue增加的语法糖computed和watch,
- React中需要自己写一套逻辑来实现(useEffect(()=>{},[xxx])) (6)
- Vue中props是可以动态变化的,子组件也实时更新
- react中官方建议props要像纯函数那样,输入输出一致对应,而且不太建议通过props来更改视图
Vue的优缺点
优点:
- 易上手: Vue.js包含基于HTML的标准模板,可以更轻松地使用和修改现有应用程序。
- 更顺畅的集成:无论是单页应用程序还是复杂的Web界面,Vue.js都可以更平滑地集成更小的部件,而不会对整个系统产生任何影响。
- 更好的性能,更小的尺寸:它占用更少的空间,并且往往比其他框架提供更好的性能。
- 精心编写的文档:通过详细的文档提供简单的学习曲线,无需额外的知识; HTML和JavaScript将完成工作。
- 适应性:整体声音设计和架构使其成为一种流行的JavaScript框架。它提供无障碍的迁移,简单有效的结构和可重用的模板。
缺点:与Angular和React相比,Vue.js框架的市场份额仍然很小。Vue的社区活跃度相对React要低.
React的优缺点
优点:
- 灵活性和响应性:它提供最大的灵活性和响应能力。
- 丰富的JavaScript库:来自世界各地的贡献者正在努力添加更多功能。
- 可扩展性:由于其灵活的结构和可扩展性,React已被证明对大型应用程序更好。
- 不断发展: React得到了Facebook专业开发人员的支持,他们不断寻找改进方法。
- Web或移动平台: React提供React Native平台,可通过相同的React组件模型为iOS和Android开发本机呈现的应用程序。
缺点: 学习成本高,陡峭的学习曲线:由于复杂的设置过程,属性,功能和结构,它需要深入的知识来构建应用程序。
3.Vue的双向数据绑定原理是什么?
Vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
- 第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
- 第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
- 第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。 - 第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
4.Vue中render函数
render函数主要是在main.js中使用
// 创建vue实例
new Vue({
// 完成这个功能,将App放入容器中
render: h => h(App), //完整写法为render:function(createElement){return createElement(App)}
}).$mount('#app')
createElement 函数是用来生成 HTML DOM 元素的,而Hyperscript本身是指生成HTML 结构的 script 脚本,这样作者才把 createElement 简写成 h。
createElement(也就是h)是vuejs里的一个函数。这个函数的作用就是生成一个 VNode节点,render 函数得到这个 VNode 节点之后,返回给 Vue.js 的 mount 函数,渲染成真实 DOM 节点,并挂载到根节点上。
5.Vue.set(vm.set)使用
当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中直接以赋值的形式添加新的属性,如果更新此属性的值,是不会更新视图的。
原因: Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
解决:使用 Vue.set(object, key, value) 方法可以将响应属性添加到嵌套的对象上
target:要更改的数据源(可以是对象或者数组)
key:要更改的具体数据
value :重新赋的值
(例如:Vue.set(vm.obj, 'e', 0))
6.当发生路由跳转时会触发哪些生命周期钩子
路由发生跳转时完整执行过程:
(1)导航被触发
(2)执行 组件内部路由守卫: beforeRouteLeave(如果是嵌套路由无此操作)
(3)执行 全局路由守卫 beforeEach
(如果是嵌套路由这里会有执行父路由的beforeRouteUpdate)
(4)执行路由中的钩子 beforeEnter
(5)在被激活的组件里调用 beforeRouteEnter
(6)执行 全局的 beforeResolve 守卫 。
(7)执行 全局的 afterEach 钩子
(8)beforeCreate
(9)created
(10)beforeMount
(11)执行 beforeRouteEnter的next的回调 ,创建好的组件实例会作为回调函数的参数传入。
(12)上一个组件的destroyed(如果是嵌套路由无此操作)
(13)mounted
注意:如果设置了
<keep-alive>
<router-view></router-view></keep-alive>
这个时候不会触发生命周期的钩子函数。
7.请简述下Vuex的原理和使用方法
一个应用可以看作是由上面三部分组成: View, Actions,State,数据的流动也是从View => Actions => State =>View 以此达到数据的单向流动.但是当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
Vuex采用集中式存储管理应用的所有组件的状态,可以被看作项目中所有组件的数据中心,任何组件都可以访问和操作我们的数据中心.
一个实例化的Vuex.Store主要由state, mutations和actions三个属性组成:
state中保存着共有数据
改变state中的数据有且只有通过mutations中的方法,且mutations中的方法必须是同步的
如果要写异步的方法,需要些在actions中, 并通过commit到mutations中进行state中数据的更改.
8.什么是MVVM
MVVM即Model层(数据模型层),View层(视图层),ViewModel层(视图模型层)
Model层(数据模型层:通过Ajax/Fetch等API完成客户端和服务端业务模型同步
View层(视图层):作为视图模板存在,其实View就是一个动态模板
ViewModel层(视图模型层):负责暴露数据给View层,并对View层中的数据绑定声明,指令声明,事件绑定声明,进行实际的业务逻辑实现.
数据变化了,视图更新=>ViewModel底层会做好监听Object.defineProperty,当数据变化时,View层会自动更新
视图变化了,绑定数据更新=>会监听双向绑定的表单元素值的变化,一旦变化,绑定的数据会得到自动更新.
9.前端如何实现即时通讯?
即时通讯需求:服务端信息更新,需要通知客户端
严格意义上http协议只能够做到哪客户端向服务器端请求数据,服务器端做出响应,做不到服务器端主动向客户端响应消息
基于web前端,存在以下几种可实现即时通讯的方法:
(1)短轮询:服务器端定时向服务器端发送消息,获取服务器端的最新数据,一定程度模拟即时通讯,不是真正的即时通讯
缺点:实时性差,占用资源
(2)长轮询:浏览器向服务端发送请求,服务端收到请求后会阻塞请求直到有数据返回或者超时才返回,浏览器收到请求后会再次发出请求,服务端会再次阻塞请求直到有数据返回或者超时才返回
缺点:服务器压力大
(3)SSE:服务端推送事件,他是基于HTTP协议,允许服务端向客户端推送新数据的HTML5技术--流信息(每次发出的都是新请求)
缺点:基于HTTP协议不是严格的双向通信,基于文本传输,没有WebSocket效率高
(4)WebSocket:基于TCp协议的全新/独立的协议,实现服务器和客户端之间建立实时的双向通信.WebSocket协议与TCp协议保持兼容,但不会融入HTTP协议,只是作为HTML5的一部分
优点:真正意义上的即时通信,性能好,延迟低
缺点:使用时需要对项目进行改造,学习成本相对较高
10.你们公司的Git工作流是怎么样的?
在GitFlow标准下,我们的git仓库需要包含一下几个关键分支:
- master:主分支
- develop:主开发分支.包含确定即将发布的代码
- feature:新功能分支.一个功能对应一个分支
- release:发布分支.发布时用的分支,一般测试阶段发现的bug在这个分支上进行恢复
- hotfix:热补丁分支.用于修改在线上版本中发现的眼中那个紧急bug
回答方法:
- 有一个dev分支,写新功能,在dev分支上新开分支,写功能
- 功能写完了,合并到dev分支上
- 将dev分支上新增的功能合并到release分支,进行测试,修复bug..
- 将修复好的release分支的代码合并到master和dev上
- jiangmaster的代码,用于真实上环境的上线
- 如果上线代码遇到bug,开一个hotfix的分支,挑食bug,紧急修复
11.Babel的原理是什么?
Babel的作用是对代码进行转译(解决兼容,解析执行一部分代码)
let a = 1 + 1 => var a = 2
转译分成三个阶段:
- 解析:将代码装换成抽象语法树,也就是此法分析于语法分析过程
- 转换:对语法树济宁变换方面的一系列操作.通过Babel-traverse,进行遍历并添加/更新/删除等操作
- 生成:通过babel-generator将变换后的AST转换为Js代码
12.Vue中key的作用
key是为Vue中的虚拟Dom节点(VNode)标记唯一的ID(优化复用对比策略,优化渲染性能)
vue中的更新机制(差异化更新)对比新旧虚拟DOM,找出不同的部分,进行更新视图
diff算法:默认的对比(diff)机制,同层兄弟元素,是按照下标(索引)进行对比的,但是加了key,就相当于给虚拟dom加了个标识,对比策略就是对相同key的元素进行对比,常用于v-for中.
13.什么是作用域
简单来说:指程序中定义变量的区域,它决定了当前执行代码对变量的访问权限
ES6之前:
- 全局作用域:全局作用域为程序最外层的作用域,一直存在
- 函数作用域:函数作用域只有函数被定义时才会被创建,包含在父级函数作用域、全局作用域内
ES6之后:
- 块级作用域:大括号{} 内部使用let/const声明变量
由于作用域的限制,每段独立的执行代码块只能访问自己的作用域和外层作用域中的变量,无法访问到内层作用域的变量
14.es6有哪些属性
- let、const
- 解构赋值
- 模板字符串
- 箭头函数
- 函数默认值
- promise
- set、map结构
- class类
- symbol
- Iterator 和 for...of 循环.
- 数组的扩展方法
15.什么是闭包?
在MDN的解释中,闭包是一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。即闭包= 函数 + 外层函数的环境的引用。
闭包的作用:封闭数据,提供操作。
闭包理解的误区:
- 误区1:闭包会造成内存泄漏。内存泄漏是指:我们再也用不到(无法访问到)的变量,依然占着内存空间。而闭包内部的变量是可以访问到呀,所以不应该归到内存泄漏中去。
- 误区2:闭包比较复杂,写代码尽量别写闭包。以现在前端代码的复杂程度,没有闭包的代码决计不可能发生!
- 误区3:只有js中才有闭包,这是错误的,闭包并不是针对某种特定语言的概念,而是一个通用概念
16.什么是作用域链?
当可执行代码内部访问变量时,会先查找本地作用域,如果找到目标变量即返回,否则会去父级作用域继续查找...一直找到全局作用域。我们把这种作用域的嵌套机制,称为作用域链。
17.什么是垃圾回收机制和内存泄漏?
垃圾回收机制:程序的运行需要内存,只要程序提出要求,操作系统或者运行时就必须提供内存,为了保证持续运行服务进程,必须要及时释放内存,否则,内存占用越来越高,轻则影响系统性能,重则就会导致进程崩溃,垃圾回收机制的原理说白了也就是定期找出那些不再用到的内存(变量),然后释放其内存.最常见的是(标记清除算法,引用计数算法)
早期的垃圾回收机制使用的是引用计数法,但是如果出现循环引用会造成内存泄漏,现在的浏览器大多是是基于标记清除算法的改进算法(从js根部触发,无法访问到,无法初级,这块空间就是垃圾,需要被回收)
内存泄漏:无用的内存还在占用,得不到释放和归还。比较严重时,无用的内存会持续递增,从而导致整个系统卡顿,甚至崩溃。
内存的生命周期:
- (1)内存分配:当我们声明变量,函数,对象的时候,系统会自动为他们分配内存
- (2)内存使用:即读写内存,也就是使用变量,函数等
- (3)内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存,全局变量一般不会回收,一般局部变量的值,不用了会被自动回收
常见的导致内存泄漏的情况:
- 意外的全局变量
- 被遗忘的定时器
- 被遗忘的事件监听器
18.什么是原型对象,原型链及原型链的作用
原型对象:我们创建的每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象包含了通过调用该构造函数所创建的对象共享的属性和方法。
原型链:当我们访问某个对象的属性时,要沿着某个路径去找这个属性,这条路径就是原型链。
例如我们需要查找p属性:
- (1)先在自有属性中找,如果找到,则返回;如果找不到,则进入到它的隐式原型中去找。
- (2)由于对象的隐式原型也是一个对象(对象又是属性的集合),所以继续在
obj.__proto__的自有属性中去找。找到则返回,找不到,则继续。 - (3)在
obj.__proto__这个对象的隐式原型中继续找。找到返回,找不到,则继续到obj.__proto__.__proto__中去找。 - (4)直到
__proto__为null 停止。
原型链的应用:把属性(或者是方法)添加在构造器的原型对象上后,由此构造器创建的对象均可以使用这个属性(方法),如果直接在构造器中添加属性和方法,虽然实例化的对象都能够拥有,但是每个对象相同属性和方法指向的地址是不同的。
19.你们公司做了什么缓存控制?
web服务缓存大致可以分为:数据库缓存、服务器缓存(代理服务器缓存,CDN服务器缓存),浏览器缓存。 浏览器缓存包含:HTTP缓存、indexDB、cookie、localstorage等等
HTTP缓存:(优化页面加载的效率,如果没有缓存策略,每次重新加载页面,会非常慢)
- 强缓存
- 协商缓存
缓存术语:
- 缓存命中率:从缓存中得到数据的强求书,所有请求书的比率。理想状态是越高越好
- 过期内容:超过设置的有限时间,被标记为“陈旧”的内容
- 验证:验证缓存中的过期内容是否有效,验证通过的话刷新过期时间
- 失效:失效就是把内容从缓存中移除 浏览器主要是HTTP协议定义的缓存机制
20.请描述整体缓存请求流程
21.请简述一次完整的http服务过程
22.object.defineProperty这个API有哪些属性和方法
格式: Object.defineProperty(obj, prop, descriptor)
- obj:要操作的对线能够
- prop:要定义或修改的属性名称
- descriptor:对参数prop的描述,也叫属性描述符,同时一个具有固定属性名的字面量对象
value: undefined, // 初始值,该属性对应的初值
writable: false, // 可写入,为true时,value属性值才能够被修改
configurable: false, //可配置,为true时,属性才能够使用defineProperty重新定义或者删除
enumerable: false, // 可枚举,为true时,该属性才能够出现在对象的描述属性中,即可以使用for in循环访问
get:function(){}, // 当访问该属性时,该方法会被执行
set:function(){} // 当属性值被修改时,触发执行该方法,该方法将接受唯一参数,即要给此属性赋的新值
注:get和set 不能够和value与writable同时使用
23.观察者和发布订阅者模式的区别
在不是特别的严格的情况下,可以认为观察者 == 发布订阅者模式
// 观察者模式
function EventCenter(){
this.guanjia = []
}
// 添加观察者
EventCenter.prototype.$on = function(listener){
this.guanjia.push(listener)
}
// 通知观察者去执行
EventCenter.prototype.$emit = function(){
this.guanjia.forEach(fn => fn())
}
//发布订阅者模式
function EventContainer(){
this.guanJia ={}
}
EventContainer.prototype.$on=function(eventName,callBack){
if(this.guanJia[eventName]){
this.guanJia[eventName].push(callBack)
}else{
this.guanJia[eventName]=[callBack]
}
}
EventContainer.prototype.$emit=function(eventName){
if(this.guanJia[eventName]){
for(let fn of this.guanJia[eventName]){
fn()
}
}
}
const app = new EventContainer()
app.$on('a',()=>{
console.log('a1');
})
app.$on('a',()=>{
console.log('a2');
})
app.$emit('a')
24.实现一个简单的MVVM模型
function EventContainer(){
this.guanJia ={}
}
EventContainer.prototype.$on=function(eventName,callBack){
if(this.guanJia[eventName]){
this.guanJia[eventName].push(callBack)
}else{
this.guanJia[eventName]=[callBack]
}
}
EventContainer.prototype.$emit=function(eventName){
if(this.guanJia[eventName]){
for(let fn of this.guanJia[eventName]){
fn()
}
}
}
// 实例化一个观察者模式
const ec = new EventContainer()
function MVVM(option){
const {el, data} = option
for(let key in data){
Object.defineProperty(this, key, {
set:function(newVal){
if(newVal !== data[key]){
// 1.保存新值
console.log(`有人修改了${key},值为${newVal}`)
data[key] = newVal
}},
get:function(){
console.log(`有人获取了${key}的属性值`)
return data[key]
}}
)
}
const rootDom = document.querySelector(el)
// 把伪数组转换成数组:Array.from()
Array.from(rootDom.children).forEach(node => {
// 把v-html这个属性的属性值(xxxx)取出来
// 在数据项找到这个值,并显示出来
if(node.hasAttribute('v-html')){
let key = node.getAttribute('v-html')
node.innerHTML = this.xxxx
// 添加一个观察者.作用:当数据变化时,能更新视图
ec.$on(key, () => {
node.innerHTML = this[key]
})
}
if(node.hasAttribute('v-model')){
let key = node.getAttribute('v-model')
node.value = this.xxxx
// 添加一个观察者.作用:当数据不拜年话是,能更新视图
ec.$on(key, () => {
node.value = this[key]
})
// 监听input框中的input事件,当事件发生时,把用户输入的值设置到数据项中
node.addEventListener('input',(e)=>{
this[key] = e.target.value
})
}
})
}
25.vue的整个编译过程
我们知道直接访问DOM是非常昂贵的,会造成相当多的性能浪费,所以我们试想,当某个状态发生变化时,只更新于这个状态相关联的DOM节点.虚拟DOM就是解决方案之一
Watcher:每个Vue组件都有一个对应的watcher,这个watcher将会在组件render的时候收集组件所依赖的数据,并在依赖有更新的时候,触发组件的重新渲染.
1.template,el的作用就是用来生成渲染函数
2.用渲染函数+当前数据->虚拟DOm
3.虚拟DOm->真实的dom
通过render函数把整个过程分成两部分:
26.为什么vue3要用Proxy来代替Object.defineProperty
(1)效率更高
- proxy可以处理一类动作
- Object.defineProperty只能处理某个具体属性名 (2)prox能直接监控数组的操作:
- 数组长度的变化并不会直接更新页面
- 通过数组下标去修改数组元素,页面也不会更新 vue2.0对数组响应式的实现不是通过Object.defineProperty,而是直接拦截了7个处理数据的方法:只有在调用这7个方法(pop,shift,push,unshift,sort,reverse,slice)时,vue2才能够感知数组的变化,进而去更新视图 (3)proxy返回的是一个对象,我们可以只操作新对象达到目的,而另外一个只能遍历对象属性直接修改
27.定义渲染函数的三种方式
28.HTTP的keep-alive是什么作用?
29.HTTP请求报文和响应报文的组成
30.你了解的HTTP状态码有哪些?
31.GET和post方法的区别
32.浏览器是如何进行界面渲染的
不同的渲染引擎的具体做法稍有差异,但是答题流程都是差不多的,下面以chrome渲染引擎的渲染流程来说明:
浏览器开始渲染:
- 1.解析最新的html结构,生成DOM树
- 2.同时解析最新的css样式,生成样式规则rules
- 3.将DOM树和样式规则结合 => 生成render Tree渲染树
- 4.基于渲染树,进行运算布局(重排)
- 5.进行绘制(重绘)
33.什么是重排(回流)和重绘
重排:重排是指部分或整个渲染树需要进行重新分析,并且节点的尺寸需要重新计算(表现为重新生成布局,重新排列元素) 重绘:重绘是由于节点的集合属性发生改变,或由于样式发生改变(表现为某些元素的外观被改变,或者重排后进行重绘)
重排一定会进行重绘,但是重绘不一定进行重排
每个页面至少需要一次重排+重绘(初始化渲染)
频繁重排和重绘会破坏用户体验,让页面显示变得迟缓,尽量避免,尤其是重排.
34.何时会触发重排
35.重绘重排的角度,我们应该如何优化页面渲染性能?
依次进行对此重排和重绘操作,十分消耗性能,浏览器会对这些操作进行优化,浏览器会维护一个队列,把所有会引起重排和重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理,这样就会让对此的重排和重绘变成一次的重排重绘.
36.浏览器是按照什么方向进行解析的?
浏览器解析选择器是按早从右往左进行解析的,因为性能更高
从左往右:找后代,其实就是进行所有的后代子树的遍历,页面中医科DOM树的节点成百上千,这种遍历方式的效率会非常的低
从右往左:找父代,第一次和从左往右一样遍历整个DOM树,但是第二次只需要遍历有限的父辈
37.什么是TCP协议
TCP协议(传输控制协议)是一种面向连接(连接导向)的,可靠的,基于IP的出书层协议.使用校验/确认和重传机制来保证可靠传输.
HTTP协议就是建立在TCP协议上的一种应用.
38.谈谈你对文档片段的理解
documentFragment是一个保存多个元素的容器对象(保存在内存),当更新其中的一个或多个元素时,页面不会更新. 当documentFragment容器中保存的所有元素操作完了,只有将其插入到页面中才会更新页面.
39.伪类和伪元素的区别?
什么是伪类:伪类是以冒号: 为前缀,可被添加到一个选择器的美味的关键字,它用于让样式在元素的特定状态下才被应用到实际元素上.比如:checked,:hover,:disabled,:first-child等(伪类的权重和类是一致的)
什么是伪元素:伪元素用于创建一些不在DOM树中的元素,并未其添加样式.伪元素的语法和伪类类似,可以一个冒号或者两个冒号为前缀,比如可以通过::before/::after来在一个元素前后增加一些额外的文本并未他们添加样式.并且,虽然用户可以看到这些文本,但其实他们并不在DOM树中(伪元素是无法注册事件的,所以不要通过js控制伪元素)
40.px,em,rem之间有什么区别?
41.meta标签有哪些常见的用法
42.script标签中defer和async的使用区别
43.前端常见的集中存储方式的区别
44.什么是CSS Sprites以及它的好处
45.什么是BFC
BFC:块级格式化上下文,是一块独立的渲染区域(触发了BFC,这块区域就是一块独立的渲染区域)会将处于BFC的内容和处于BFC外的内容隔离.
触发BFC的方式:
- (1)position:absolute/fixed
- (2)float:left / right 浮动到的元素多个放在一起,会互相隔开
- (3)overflow:非visible(hidden/auto/scroll)
- (4)display:inline-block
BFC的应用:
- 1.处理块级元素,上下margin合并的问题
- 2.处理margin塌陷
- 3.清除浮动
- 4.实现自适应布局
46.谈谈你对HTML语义化的理解?
47.深拷贝和浅拷贝
原因:引用类型,进行赋值是,赋值的是地址
浅拷贝:
let obj1 = {
name:'老曹'
}
let obj2 = obj1
深拷贝:
let obj1 = {
name:'老曹'
}
let obj2 = JSON.parse(JSON.stringify(obj1))
递归方法:
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;
}
48.通过new实例化一个对象做了什么?
- 1.创建一个新对象
- 2.让构造函数的this,指向新对象
- 3.执行构造函数
- 4.返回实例
49.call,bind,apply的区别
fn.call(this指向的内容,参数1,参数2,...)
fn.apply(this指向的内容,[参数1,参数2,...])
const newFn = fn.bind(this指向的内容) 返回一个新函数,且不会立即执行
50.相较于Promise,async/await有何优势?
1.同步化代码的阅读体验(promise虽然摆脱了回调地狱,但then链式调用的阅读负担还是存在)
2.和同步代码更一致的错误处理方式(async/await可以用成熟的try/catch做处理,比Promise的错误捕获更简洁直观)
3.调试时的阅读性,也相对更友好
注:async可以用于修饰一个函数,表示一个函数是异步的
async只有在遇到await开始,才是异步的开始
51.如何实现首屏加载过慢的问题?
52.判断数据类型
- typeOf(typeof 目前能返回string,number,boolean,symbol,bigint,unfined,object,function这八种判断类型)
注:typeof null object
- instanceof 一般用来判断引用数据类型的判断,如:Object,Function,Array,Date,RegExp等
/s/g instanceof RegExp true
new Date('2019/01/05') instanceof Date true
[1,2,3] instanceof Array true
- constructor
- Object.prototype.toString(这个是判断类型最准的方法)
Object.prototype.toString.call('') ; [object String]
Object.prototype.toString.call(1) ; [object Number]
Object.prototype.toString.call(true) ; [object Boolean]
Object.prototype.toString.call(undefined) ; [object Undefined]
Object.prototype.toString.call(null) ; [object Null]
Object.prototype.toString.call(new Function()) ; [object Function]
Object.prototype.toString.call(new Date()) ; [object Date]
Object.prototype.toString.call([]) ; [object Array]
Object.prototype.toString.call(new RegExp()) ; [object RegExp]
Object.prototype.toString.call(new Error()) ; [object Error]
Object.prototype.toString.call(document) ; [object HTMLDocument]
Object.prototype.toString.call(window) ;[object global] window是全局对象global的引用
53.js的事件循环
js是单线程的,如果遇到了异步的内容,交给宿主环境(浏览器,node)处理
1.宏任务
主线程要执行的代码=>宏任务
定时器/演示器=>宏任务
注意:只用上一个宏任务执行完,才会考虑下一个宏任务
微任务 promise.then和.catch中需要执行的代码,微任务会在当前宏任务执行完,在下一个宏任务开始前执行