本文章仅仅用作记录面试过程中被问及却没有回答上来,或者回答的不清晰的面试题。
html部分
html语义化是什么?为什么要语义化?
答案:1.语义化就是根据内容的结构化,选择合适的标签,便于开发者阅读和写出更优雅代码的同时,让浏览器的爬虫和机器很好的解析。
2.为了在没有css的情况下,也能呈现出很好的内容结构,代码结构;为了用户体验:例如title,alt用于解释名字或解释图片信息,label标签的活用;有利于seo:和搜索引擎建立良好的沟通,有助于爬虫抓取更多有效信息,爬虫依赖于标签来确定上下文和各个关键字的权重;方便其他设备解析;便于团队开发和维护,语义化更具可读性,可以减少差异化。
hhtml5新增了哪些标签,css3新增了什么?
答案:html5新增标签有语义化标签:header,nav,article,aside,section,figure,details,embed,footer;媒体标签:video,audio,另外还有canvas等等。css3新增了border-color,border-image,border-radius,box-shadow;background-size,background-origin,background-clip,文字阴影,自动换行,动画效果transform,animation,过度效果:transition。
什么是BFC?它有什么作用?
回答:BFC指的就是块级格式化上下文,它是一个单独的渲染区域,只有block-level box参与,它规定了内部的block-level box如何布局,并且与这个区域外部毫不相干
规则:内部的box会在垂直方向,一个接一个的放置;box垂直方向的距离有margin决定,属于同一个bfc的相邻box的margin会发生重叠;每个格子的margin box的左边,与包含块的border box的左边相接触,及时存在浮动也是如此;bfc的区域不会与float box重叠;
创建BFC:float的值不是none,position的值不是static或者relative,display的值是inline-block,tabel-cell,flex,tabel-caption或者inline-flex,overflow的值不是visible。
作用:1.利用bfc避免margin重置;2.自适应两栏布局;3.清除浮动;
怎么清除浮动?
回答:1.为父元素添加overflow:hidden(目的是触发bfc);2.添加一个标签,并设置clear:both(缺点是语义化差);3.使用after伪类清除浮动(低版本不支持);4.使用before和after双伪类清除
浏览运行机制
重排和重绘分别是什么?
回答:重排:也叫回流,当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。
重绘:是在一个元素的外观被改动所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现出新的外观,比如改变某个元素的背景颜色/文字颜色/边框颜色等等
触发重排的方式:1.添加或删除可见的dom;2.元素的位置改变;3.元素的尺寸改变(外边距,内边距,边框厚度,宽高,等几何属性);4.页面渲染初始化;5.浏览器窗口尺寸改变;6.获取某些属性时也会重排,它会导致队列刷新,这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。
js基础
js的数据类型及判断方法
js包含五种基本数据类型:undefined, null,Boolean,number,string;
复杂类型:Object(又叫引用类型),其包含Array,data,Function
es6新增了Symbol类型,es2020新增了BigInt类型
判断:
1、可以通过typeof判断这些类型,但是判断null类型会返回object,判断所有引用类型会返回Object,
2、另外可以使用instanceof判断,比如
let a=[];
console.log(a instanceof Array) // true
console.log(a instanceof Object) // true
let a = null
console.log(a instanceof Object) // false
3、还可以使用Object.prototype.toString().call(xxx)来判断,他讲返回[Object Type]字符串,这种判断方式最准确。
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的引用
4、使用constructor判断(不好,不推荐)
原因:1.null和undefined是无效的对象,因此是不会有constructor存在的;
2.JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object
map和weakmap的区别
Map
- 本质上是键值对的集合,类似集合
- 可以遍历,方法很多可以跟各种数据格式转换
WeakMap
-
只接受对象作为键名(null除外),不接受其他类型的值作为键名
-
键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
-
不能遍历,方法有get、set、has、delete
vue部分
什么是虚拟dom?
回答:真是dom在面对频繁修改样式和结构的场景下,会频繁的触发回流和重绘,使得性能开销巨大,而vue和react中使用虚拟dom,是建立一个和dom树对应的虚拟dom对象(js对象),以对象嵌套的方式来表示dom树,那么每次dom的更改就变成了js对象属性的更改,这样一来就能查找js对象属性的变化,要比查询dom树的性能开销要小。
优缺点:优点:1.保证性能下限;2.无需手动操作dom;3.跨平台
缺点:无法进行极致优化:虽然虚拟dom+合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中,虚拟dom无法进行针对性的极致优化。
Proxy 与 Object.defineProperty 优劣对比
回答:
proxy的优势
proxy可以直接监听对象而非属性;
proxy可以直接监听数组变化;
proxy有多达13种拦截方法,不限于apply,ownkeys,deleteProperty,has等等,这是object.defineProperty不具备的;
proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而defineProperty只能遍历对象属性直接修改;
proxy作为新便准将受到到浏览器厂商的重点持续的性能优化,
object.defineProperty的优势:
兼容性好,支持ie9,而proxy存在浏览器兼容问题,而且无法使用polyfill磨平。
vue是如何实现对象和数组的监听
vue2是通过遍历数组和递归遍历对象,object。difinePropety也能对对象和数组进行监听。
在vue created或者mounted阶段可以修改data中的数据吗?
回答:不可以,因为在created或者mounted阶段,this指向的是window作用域,所以会出现获取不到data中的数据出现没有定义的情况。解决:使用var that = this来改变this指向。
vue组件中的data为什么是函数而不是对象?什么情况下可以使用对象?
回答:首先vue组件中的data是个函数,是因为组件可能存在多个实例,如果data是一个对象,则会导致他们公用一个data对象,那么状态变更会影响所有组件实例;如果data是一个函数,那么在initData时会将其视作工厂函数,返回一个新的data对象,有效规避多实例之间状态污染的问题。一般情况下,创建vue根实例,即new Vue()的时候,data可以是一个对象。或者在只有一个vue组件的场景下。
vue中key的作用和工作原理?说说你对他的理解
回答:key的主要作用是为了高效的更新虚拟dom,其原理是vue在patch的过程中通过key可以精准地判断两个节点是否是同一个,从而避免频繁更新不同元素,是的整个patch过程更加高效,减少dom操作量,提高性能。
另外,若不设置key,还可能在列表更新是引发一些隐蔽的bug。
vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
怎么理解vue中的diff算法?
回答:1.diff算法是虚拟dom技术的必然产物,通过新旧虚拟dom作对比,将变化的地方更新在真实的dom上,另外,也需要diff高效地执行对比过程,从而降低时间复杂度为o(n)。
2.必要性:vue2.x中为了降低Watcher粒度,每个组件都有一个Watcher与之对应,只有引入diff才能精确找到发生变化的地方,所以需要diff。
3.vue中diff执行的时刻是组件实例执行其更新函数时,他会比对上一次渲染结果oldVnode和新的渲染结果newVnode,此过程称之为patch。
4.diff过程整体遵循深度优先,同层比较的策略;两个节点之间比较会根据他们是否拥有子节点或者文本节点做不同操作;比较两组子节点是算法的重点,首先假设头尾节点可能相同,做4次对比尝试,如果没有找到相同节点,才按照通用方式遍历查找,查找结束再按情况处理剩下的节点(要么删除,要么新增);借助key通常可以非常精确找到相同节点,因此整个patch过程非常高效。
谈一谈对vue组件化得理解
回答:1.组件是独立和可复用的代码组织单元。组件系统是vue核心特性之一,它使开发者使用小型、独立和通常可复用的组件攻坚大型应用;
2.组件化开发能大幅提高应用开发效率、测试性能、复用性等;
3、组件使用按分类有:页面组件,业务组件,通用组件;
4.vue的组件是基于配置的,我们通常编写的组件是组件配置而非组件,框架后续会生成其构造函数,它们基于vueComponent,扩展于vue;
5.vue中常见的组件化技术有:属性prop,自定义事件,插槽等,它们主要用于组件通信、扩展等;
6.合理的划分组件,有助于提升应用性能;
7.组件应该是高内聚、低耦合的;
8.遵循单项数据流的原则。
vue的性能优化方法
1.路由懒加载的设置,()=>import('...')
2.keep-alive
3.v-show和v-if的区分使用
4.v-for上不使用v-if
6.长列表性能优化:object.freeze(args)冻结数据;虚拟滚动。
7.事件的销毁
8.图片懒加载
9.第三方资源/插件按需引入
10.无状态组件,标记为函数组件 :在template上加上functional标记
11.子组件分割
12.使用本地化变量,即使用 let xx = this.xx
13.ssr
vue3.0的新特性
回答:
更快: 1.虚拟dom重写,2.优化slots的生成,3.静态树提升,4.静态属性提升,5.基于proxy的响应式系统
更小:通过摇树优化核心库体积
更容易维护:typeScript + 模块化
更友好:支持跨平台:编译器核心和运行时核心与平台无关,是的vue更容易与任何平台(web,android,ios)一起使用
更容易使用:typescript支持,编译器能提供强有力的类型检测和错误及警告,独立的响应化模块,composition API
hash和history的区别
hash**:****比如这个 URL:www.aaa.com/#/hello,has… 的值为 #/hello。它的特点在**于: hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
history: 利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)
两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
因此可以说,hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。
history模式的问题:
通过history api,我们丢掉了丑陋的#,但是它也有个问题:不怕前进,不怕后退,就怕刷新,f5,(如果后端没有准备的话),因为刷新是实实在在地去请求服务器的。
在hash模式下,前端路由修改的是#中的信息,而浏览器请求时不会将 # 后面的数据发送到后台,所以没有问题。但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,则会刷新出来404页面。