1、v-model默认的触发条件是input事件,加了.lazy修饰符之后,v-model会在change事件触发的时候去监听
2、:class 绑定变量 绑定对象 绑定一个数组 绑定三元表达式
:style 绑定变量 绑定对象 绑定函数返回值 绑定三元表达式
3、 组件中写name选项有什么作用
- 项目使用keep-alive时,可搭配组件name进行缓存过滤
- DOM做递归组件时需要调用自身name
- vue-devtools调试工具里显示的组见名称是由vue中组件name决定的
4、diff算法
(key的体现:不设key,newCh和oldCh只会进行头尾两端的相互比较,设key后,除了头尾两端的比较外,还会从用key生成的对象oldKeyToIdx中查找匹配的节点,所以为节点设置key可以更高效的利用dom。)
diff的过程就是调用patch函数,就像打补丁一样修改真实dom。
function patch (oldVnode, vnode) {
if (sameVnode(oldVnode, vnode)) {
patchVnode(oldVnode, vnode)
} else {
const oEl = oldVnode.el
let parentEle = api.parentNode(oEl) //取得oldvnode.el的父节点,parentEle是真实dom
createEle(vnode) //createEle(vnode)会为vnode创建它的真实dom,令vnode.el =真实dom
if (parentEle !== null) {
api.insertBefore(parentEle, vnode.el, api.nextSibling(oEl)) //parentEle将新的dom插入,移除旧的dom
api.removeChild(parentEle, oldVnode.el)
oldVnode = null
}
}
return vnode
function sameVnode (a, b) {
return (
a.key === b.key && // key值
a.tag === b.tag && // 标签名
a.isComment === b.isComment && // 是否为注释节点
// 是否都定义了data,data包含一些具体信息,例如onclick , style
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b) // 当标签是的时候,type必须相同
)
}
如果两个节点是一样的,那么就深入检查他们的子节点。如果两个节点不一样那就可以直接替换oldVnode:
当我们确定两个节点相同之后我们会对两个节点执行patchVnode方法:
当两个节点值得比较时
function patchVnode (oldVnode, vnode) {
const el = vnode.el = oldVnode.el
let i, oldCh = oldVnode.children, ch = vnode.children
if (oldVnode === vnode) return
if (oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text) {
api.setTextContent(el, vnode.text)
}else {
updateEle(el, vnode, oldVnode)
if (oldCh && ch && oldCh !== ch) {
updateChildren(el, oldCh, ch)
}else if (ch){
createEle(vnode) //create el's children dom
}else if (oldCh){
api.removeChildren(el)
}
}
}
这个函数做了以下事情:
找到对应的真实dom,称为el
判断Vnode和oldVnode是否指向同一个对象,如果是,那么直接return
如果他们都有文本节点并且不相等,那么将el的文本节点设置为Vnode的文本节点。
如果oldVnode有子节点而Vnode没有,则删除el的子节点
如果oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化之后添加到el
如果两者都有子节点,则执行updateChildren函数比较子节点,这一步很重要
对比当前真实的DOM和虚拟DOM,在对比过程中直接更新真实DOM
只对比同一层级的变化
节点比较时有5中情况
- if (oldVnode === vnode),他们的引用一致,可以认为没有变化。
- if(oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text),文本节点的比较,需要修改,则会调用Node.textContent = vnode.text。
- if( oldCh && ch && oldCh !== ch ), 两个节点都有子节点,而且它们不一样,这样我们会调用updateChildren函数比较子节点,这是diff的核心,后边会讲到。
- else if (ch),只有新的节点有子节点,调用createEle(vnode),vnode.el已经引用了老的dom节点,createEle函数会在老dom节点上添加子节点。
- else if (oldCh),新节点没有子节点,老节点有子节点,直接删除老节点。
首屏加载优化
- 异步路由和异步加载
- 还有分屏加载, 按需加载, 延时加载图片等, cdn, 域名拆分
- webpack压缩HTML/CSS/JS,
- 首屏css单独提取内联,
- 关键资源Proload,
- 图片:不缩放,使用webp、小图片base64(3k大小,太大的话会增加css文件大小,Base64 跟 CSS 混在一起,大大增加了浏览器需要解析CSS树的耗时。),iconfont,
- gzip,
dns-prefetch, - 静态资源单独域名,去掉cookie
- 将资源放到不同的域下:浏览器同时从一个域下载资源的数目有限(chrome为6个),增加域可以提高并行下载量
- 减少回流重绘
事件捕获和事件冒泡
https://www.jianshu.com/p/c88c15c6074c
封装axios主要封装
封装处理配置(路径、时间、token)、统一管理接口、错误处理、不同形式的请求、消息提示、loading等。
div水平垂直居中
- 使用flex布局
div.parent {
display: flex;
justify-content: center;
align-items: center;
}
}
- 子元素绝对定位
div.parent {
position: relative;
}
}
div.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
- 知道子元素高度的情况下
/* 或者 */
div.child {
width: 50px;
height: 10px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -25px;
margin-top: -5px;
}
}
/* 或 */
div.child {
width: 50px;
height: 10px;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
}
div.parent {
display: grid;
}
}
div.child {
justify-self: center;
align-self: center;
}
}
div.parent {
font-size: 0;
text-align: center;
&::before {
content: "";
display: inline-block;
width: 0;
height: 100%;
vertical-align: middle;
}
}
}
div.child{
display: inline-block;
vertical-align: middle;
}
}
5
div.parent{
display:flex;
}
}
div.child{
margin:auto;
}
}
computed原理
在initComputed中遍历每一个computed属性,创建对应的Watcher。在Watcher实例化过程中,计算computed属性结果,会对依赖的data进行取值,从而触发data的getter进行依赖收集,将当前Watcher加入到订阅者数组中。当computed属性依赖的data改变时,会触发data的setter通知订阅者更新,这个computed会重新计算。
浅拷贝是拷贝一层,深层次的对象级别的就拷贝引用;深拷贝是拷贝多层,每一级别的数据都会拷贝出来;
箭头函数和普通函数的区别
1、箭头函数是匿名函数,不能作为构造函数,即不能使用new来创建对象
2、箭头函数不能绑定arguments,需要用类似语法来实现 (...a)=>{拿到的是一个数组}
3、箭头函数没有原型属性
4、箭头函数没有自己的this
flex布局
flex-container有6个属性,包括flex-direction、flex-wrap、flex-flow、justify-content、align-items、align-content
其中
1、flex-direction主要来定义主轴的方向(默认我为row,还有row-reverse、column、column-reverse)
2、flex-wrap主要定义是否换行(默认nowrap、wrap、wrap-reverse)
3、flex-flow是flex-direction和flex-wrap的集合
4、justify-content用来定义项目在主轴上的对齐方式(flex-start,flex-end,center,space-between,space-around(2倍),space-evenly(均分))
5、align-items用来定义项目在交叉轴上如何对齐(flex-start,flex-end,center,baseline,stretch(默认值,如果item没有高度则会拉伸至整个container高度))
baseline是以文本基线来对齐的(项目的第一行文字的基线对齐)
6、align-content决定了多行的flex-items在交叉轴上的对齐方式。
和justify-content类似,不过轴换成了交叉轴
每一个item上也有6个属性,分别为order、flex-grow、flex-shrink、flex-basis、flex、align-self
(1)其中order定义每个item的排列顺序,数值越小排列越靠前
(2)flex-grow定义项目的放大比例,默认为0,即如果存在剩余空间也不放大。
flex-grow决定了items如何扩展,当flex container在主轴方向上有剩余size的时候flex-grow才会生效。
----若所有items的flex-grow总和sum超过1,每个flex item扩展的size为剩余的sizeflex-grow/num
----若总和不超过1,每个item扩展的size为剩余的sizeflex-grow
前端安全:
xss攻击,sql注入,CSRF攻击
前端性能优化
(1)资源的合并于压缩html压缩,css压缩,js压缩与混乱,公共文件合并
(2)服务端开启gzip
(3)懒加载 预加载
(4)缓存,分级缓存
200(from cache): 由expires / cache-control 控制。expires(http1.0有效)是绝对时间;cache-control(http1.1有效)是相对时间。两者都存在时,cache-control 覆盖 expires,只要没有失效,浏览器只访问自己的缓存。
304 : 由 last-modified / etag 控制。当上一层失效时或用户点击refresh,F5时,浏览器就会发送请求给服务器,如果服务器端没有变化,则返回304给浏览器。
200 :当浏览器本身没有缓存或者上一层失效时,或者用户点击了CTL + F5 时,浏览器直接去服务器下载最新数据。
url从输入到呈现经历的步骤。(性能优化)
1、浏览器查缓存,有直接返回,没有则从服务器取。
2、解析协议,主机,端口,path,开启网络线程
(每一个tab页面可以看作是浏览器内核进程,然后这个进程是多线程的,它有几大类子线程)
- GUI线程
- JS引擎线程
- 事件触发线程
- 定时器线程
- 网络请求线程
3、组装http报文
4、浏览器获取主机ip地址(dns 浏览器、本机、hosts)
DNS Prefetch 是让具有此属性的域名不需要用户点击链接就在后台解析,而域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验 。
5、拿到主机地址后,打开一个socket与主机建立三次握手
6、建立成功后发送http请求
7、服务器接收请求报文并解析。(若请求头中包含缓存验证,如果命中则返回304状态码)
8、服务器将相应报文返回浏览器
9、浏览器检查报文头中缓存信息,确认是否缓存
10、如果是gzip则先解码,后根据资源类型决定如何处理
11、解析html文档。
构建dom树,
解析过程中遇到图片、样式表、js文件则启动下载
构建cssom树
根据dom和cssom树构建渲染树(从dom树的根节点遍历所有可见节点)
for in和for of
for ... in 循环返回的值都是数据结构的 键值名。
遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。
for ... in 循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键。如——例3
特别情况下, for ... in 循环会以任意的顺序遍历键名
总结一句: for in 循环特别适合遍历对象。
for of 循环用来获取一对键值对中的值,而 for in 获取的是 键名
一个数据结构只要部署了 Symbol.iterator 属性, 就被视为具有 iterator接口, 就可以使用 for of循环。
例1这个对象,没有 Symbol.iterator这个属性,所以使用 for of会报 obj is not iterable
for of 不同与 forEach, 它可以与 break、continue和return 配合使用,也就是说 for of 循环可以随时退出循环。
提供了遍历所有数据结构的统一接口
html全局属性
clas contenteditable (h5新加) dir(元素中文字的方向) id hidden spellcheck (表明浏览器是否应该对元素的内容进行拼写检查) style title
meta中viewpoint的作用
如果不定义viewpoint的话,页面宽度以屏幕分辨率为基准,而设置以后可以根据设备宽度来调整页面,达到适配终端大小的效果
css加载方式
1、外部样式表 style link
2、内部样式style里写样式
3、@import引入
4、内联样式,即直接在标签里写
inline元素特点
inline元素的margin和padding属性,水平方向的padding-left, padding-right, margin-left, margin-right都产生边距效果;但竖直方向的padding-top, padding-bottom, margin-top, margin-bottom不会产生边距效果。
Object.create()方法创建一个新对象,使用现有对象来提供新创建的对象的proto
document
document.ready 和 window.onload 的区别是:上面定义的document.ready方法在DOM树加载完成后就会执行,而window.onload是在页面资源(比如图片和媒体资源,它们的加载速度远慢于DOM的加载速度)加载完成之后才执行。也就是说$(document).ready要比window.onload先执行。
js继承的6种方式
- 原型链继承
function Person(name){
this.name = name
}
function Son(){
this.name = "son"
}
Son.prototype = new Person()
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
- 借用构造函数继承
func Son(){
Person.call(this,'son2')
}
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
- 组合继承(组合原型链继承和借用构造函数继承)(常用)
function Son(name){
Person.call(this, name)
}
Son.prototype = new Person()
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
- 最完美的继承
function Parent4(){
this.name = "parent4";
this.colors = ["red","blue","yellow"];
}
Parent4.prototype.sex = "男";
Parent4.prototype.say = function(){console.log("Oh, My God!")}
function Child4(){
Parent4.call(this);
this.type = "child4";
}
Child4.prototype = Object.create(Parent4.prototype);
Child4.prototype.constructor = Child4;
//Object.create是一种创建对象的方式,它会创建一个中间对象
清除浮动
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix:after{/伪元素是行内元素 正常浏览器清除浮动方法/
content: "";
display: block;
height: 0;
clear:both;
visibility: hidden;
}
.clearfix{
zoom: 1;/ie6清除浮动的方式 号只有IE6-IE7执行,其他浏览器不执行/
}
typeof除了null以外都可以显示正确的类型,对象和数组都返回object
instanceof主要来判断引用类型,原理是根据原型链来查找。
除了undefined、null、false、NaN、''、0、-0以外的值都会被转为true,包括所有的引用类型,即使是空的。
promise构造函数内的代码是同步执行的,之后的then或catch方式是异步执行的。构造函数接收两个参数,resolve和reject。
eventloop的理解
js的执行机制简单来说就是先执行同步代码,然后执行异步代码,而异步代码里又分为宏任务代码和微任务代码,先执行微任务,然后执行宏任务。
- 将所有js作为一个宏任务,遇到同步代码就执行,然后开始分配任务,遇到宏任务就把他们的回调分配到宏任务的队列里,遇到微任务就把他们的回调分配到微任务的队列里,然后开始执行所有的微任务。
- 执行微任务的过程还是遵循先同步然后分配异步任务的顺序,微任务执行完毕之后,一次eventloop的tick就完成了。接着挨个去执行分配好的宏任务,在每个宏任务里又先同步后异步分配任务,完成下一次tick,循环往复
34、浏览器或元素的各种距离参数。
解决跨域
- jsonp
- 设置头部Access-Control-Allow-Origin
===运算符判断相等的流程是怎样的
- 如果两个值不是相同类型,它们不相等
- 如果两个值都是 null 或者都是 undefined,它们相等
- 如果两个值都是布尔类型 true 或者都是 false,它们相等
- 如果其中有一个是NaN,它们不相等
- 如果都是数值型并且数值相等,他们相等, -0 等于 0
- 如果他们都是字符串并且在相同位置包含相同的 16 位值,他它们相等;如果在长度或者内容上不等,它们不相等;两个字符串显示结果相同但是编码不同==和===都认为他们不相等
如果他们指向相同对象、数组、函数,它们相等;如果指向不同对象,他们不相等
==运算符判断相等的流程是怎样的
- 如果两个值类型相同,按照===比较方法进行比较
- 如果类型不同,使用如下规则进行比较
- 如果其中一个值是 null,另一个是 undefined,它们相等
- 如果一个值是数字另一个是字符串,将字符串转换为数字进行比较
- 如果有布尔类型,将true 转换为 1,false 转换为 0,然后用==规则继续比较
- 如果一个值是对象,另一个是数字或字符串,将对象转换为原始值然后用==规则继续比较
其他所有情况都认为不相等(例如a = {} , a=="[object Object]"就返回true)
38、cookie 属性有名,值,max-age,path, domain,secure;
进行网站性能优化
dns方面
1、减少dns查询
2、DNS Prefetch 是让具有此属性的域名不需要用户点击链接就在后台解析,而域名解析和内容载入是串行的网络操作,所以这个方式能减少用户的等待时间,提升用户体验 。content 方面
1.减少http请求(雪碧图,小图片base64)
2.组件懒加载
3.前后端进行数据交互时尽量使用json格式,数据处理方便,资源偏小。server方面
1.添加 Expires 或者 Cache-Control(max-age、no-store、no-cache、public、private) 响应头
2.开启gzip
3.避免空 src 的 img 标签(当 标签的 href 属性为空,或