从输入网址到页面显示的过程?
DNS解析
发起TCP连接(三次握手、四次挥手)
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
连接结束
HTML页面渲染过程?
解析HTML文件,创建DOM树
解析CSS,形成CSS对象模型
将CSS与DOM合并,构建渲染树
布局和绘制
对Vue的理解?
用于创建用户界面的开源JavaScript框架
用于创建单页面的Web应用框架
用于创建用户界面的渐进式MVVM框架
Vue关注的核心是MVC模式中的视图层
Vue便于与第三方库或既有项目整合
双向绑定的原理?
MVVM模型:
Model:数据层 View:视图层 ViewModel:业务逻辑层
ViewModel:将视图和数据关联起来,由监听器和解析器组成
1、Vue实例初始化,对data执行响应化处理,这个过程发生在监听器中
2、对模板编译,找到动态绑定的数据,从data中获取并初始化试图,这个过程发生在解析器中
3、定义一个更新函数和Watcher,将来对应数据变化时会调用更新函数
Vue生命周期?
beforeCreate:vue实例的生命周期相关属性的初始化以及事件的初始化
created:完成vue的数据注入以及数据监听操作
beforeMount:模板的解析。vue会判断实例中是否含有el属性,如果没有停止编译,知道调用vm.$mount(el)才会继续编译,接着会判断是否含有template属性,如果有将其解析为一个render function,如果没有将el指定的外部html进行解析
mounted:创建vm.$el替换el,执行了render函数,将模板进行了解析,将数据进行了动态绑定。
beforeUpdate---updated---beforeDestroy---destroyed
1、new Vue会调用_init方法
2、调用$mount方法进行页面挂载
3、挂载的时候主要通过mountComponent方法
4、执行render生成虚拟DOM
5、_update将虚拟DOM生成真实DOM结构,并渲染到页面中
组件封装
写组件---引入组件---注册组件---使用组件
组件间通信
父组件传递数据给子组件
1、子组件设置props属性,接受父组件传递过来的参数
2、父组件在使用子组件标签中通过字面量来传递值
子组件传递数据给父组件
1、子组件通过$emit触发自定义事件,第二个参数为传递的数值
2、父组件绑定监听器获取到子组件传递过来的参数
兄弟组件传递数据
1、创建一个中央时间总线Bus
2、一个兄弟组件通过$emit触发自定义事件,第二个参数为传递的数值
3、另一个兄弟组件通过$on监听自定义事件
祖先组件传递数据给子孙组件
1、在祖先组件定义provide属性,返回传递的数值
2、在后代组件通过inject接收祖先组件传递的数值
复杂关系的组件数据传递可以通过vuex存放共享的变量
路由机制
1、先引入vue,再引入vueRouter---<script src=''>
2、定义一个路由对象数组,由route路由对象组成---[{},{},{}]
3、创建路由器对象router(声明路由器对象实例)---new VueRouter
4、注册路由器对象(将路由实例对象导入vue实例对象)---router
5、使用路由(实现路由切换)---<router-link to=''>
6、路由组件显示的位置(路由出口,匹配路由组件,渲染到这个区域)---<router-view>
hash路由和history路由的区别
1、hash路由在地址栏URL上有#,而history路由没有会好看一点
2、进行回车刷新操作,hash路由会加载到地址栏对应的页面,而history路由一般就404报错了(刷新是网络请求,没有后端准备时会报错)。
3、hash路由支持低版本的浏览器,而history路由是HTML5新增的API。
状态机
1、生成仓库/状态机配置对象---五个属性可选
2、生成Vuex Store构造函数的状态机---new Vuex.Store
3、注册状态机---router
4、访问状态机中的数据---$store.state.xx或鼠标触发提交突变、分发动作
状态机的五个参数
1、State:在State中存放状态,可将状态理解为组件中的data,
只不过在state中一般存放的是组件共享的数据,而在组件内的data中一般存放组件的私有数据
2、getters:类似于computed属性,对state中的属性处理之后再返回,从state中派生出来的
默认参数为state
3、mutations:突变,同步操作,唯一修改state中数据的方式
参数为state、payload,state为默认参数类似于事件中的event,payload载荷形参
4、actions:动作,存放的是异步请求
参数为sto、payload,sto是类状态机对象解构出来{commit,dispatch,state,getters},payload同上
提交突变:sto.commit('changMsg',res);
第一个参数是触发突变的事件名称,第二个参数是获取到的后台数据
分发动作:sto.dispatch('getAll',[])
第一个参数是分发动作的事件名称,第二个参数是要传递的数据
5、modules:模块化
mapState和mapGetters写在computed中,mapMutations和mapActions写在methods中
插槽
在插槽默认模板中,可以直接访问子组件的数据,可以通过props间接访问父组件的数据。
在插槽自定义模板中,可以直接访问父组件的数据,可以通过作用域插槽间接访问子组件的数据。
混入规则
当组件和混入对象有同名选项时,这些选项会以恰当的方式合并
data:会进行合并,发生冲突时,保留组件的数据
methods、computed:methods会合并,如果对象的键名发生冲突,则保留组件的键值对
生命周期钩子函数:同名的钩子函数会被合并为一个数组,依次被调用且混入对象的先被调用
v-if和v-show的区别?
1、v-if支持v-else-if、v-else,v-show 不支持 v-else。
2、v-if对应的是元素/标签的添加或者删除。
满足条件添加元素/标签,不满足条件删除元素/标签
3、v-show对应的是元素的CSS样式中的display属性。
满足条件对应的是元素的显示 display:block,不满足条件对应的是元素的隐藏 display:none
4、v-show 不管初始条件是啥,元素总会被渲染。v-if 只有条件变为真时,才会开始渲染条件块。
5、v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
watch和computed的区别
watch:支持异步,不支持缓存
数据变化时执行异步或开销较大的操作
computed:不支持异步,支持缓存,只要依赖数据不变,就不会重新计算
变量是经过某种计算然后输出而不是直接输出
为什么在大型项目中data是一个函数而不是一个对象?
根实例对象data可以是对象也可以是函数,不会产生数据污染
组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data产生数据污染
key?
1、v-for:key 具有唯一标识当前组件不被复用
2、:key = '+new Date()',手动强制触发重新渲染
过滤器?
常见修饰符?
.stop:停止事件冒泡
.capture:在事件捕获阶段执行事件处理函数
.prevent:阻止事件默认行为
.self:只当在 event.target 是当前元素自身时触发处理函数
.once:事件处理函数执行一次后解绑
.passive:滚动行为将会立即触发 ,一般与scroll连用,能够提升移动端的性能
<keep-alive> ?
默认情况下,当组件在切换的时候都会重新创建组件。
<keep-alive> :组件实例能够被在它们第一次被创建的时候缓存下来。
Ajax
1、创建Ajax实例对象---let xhr = new XMLHttpRequest();
2、打开一个连接---xhr.open(请求方式,请求路径),其中请求方式为必填参数
①get请求:地址栏请求字符串,要用qs转换js对象---Qs.stringify()
②post请求:参数携带在请求体send()中
设置请求头为表单格式,发送请求时要用qs转换js对象---Qs.stringify()
设置请求头为JSON格式,发送请求时要用JSON转换js对象---JSON.stringify()
3、发送请求---xhr.send();
4、接收响应---xhr.onreadystatechange = function(){ }
get和post的区别
1、get,参数url可见;post,参数url不可见
2、get请求是可以缓存的;post请求不可以缓存
3、get一般传输数据大小较小;post请求传输数据的大小较大
4、原则上post肯定要比get安全
cookie、localStorage和sessionStorage的区别
cookie生命期为只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
localStorage生命周期是永久的,关闭页面或浏览器之后 localStorage 中的数据也不会消失。
sessionStorage 的生命周期是仅在当前会话下有效。
http状态码
1xx:信息提示,表示临时的响应。
2xx:成功,表示服务器成功地接受了客户端请求。
3xx:重定向,表示客户端浏览器必须采取更多操作来实现请求。
4xx:客户端错误
5xx:服务器错误
BFC
直译为块级格式化上下文,可以理解成一块独立的渲染区域,BFC看成元素的一种属性。
当元素拥有了BFC属性后,这个元素就可以看做隔离了的独立容器,容器内的元素不会影响容器外的元素。
overflow值不为visible的元素 html根元素 display
避免外边距重叠 清除浮动 阻止元素被浮动元素覆盖
伸缩盒布局,弹性盒布局(display:flex)
给容器父元素使用,将子元素放在一行排列布局
垂直居中
法一:父元素设置border,子元素设置border和margin
法二:父元素设置padding和边框盒子
法三:子元素绝对定位,父元素相对定位,并且给子元素设置定位属性全部为0(top、left、bottom 、right),margin:auto
法四:子元素绝对定位,父元素相对定位,并且给子元素设置定位属性top:50%,left:50%,margin-left:-width/2,margin-top:-height/2
法五:父元素设置伸缩盒布局,在父元素中设置子元素在主轴和交叉轴的对齐方式都为居中(display: flex; justify-content: center; 和 align-items: center;)
文本溢出显示省略
text-overflow: ellipsis; white-space: nowrap; overflow: hidden;
link和@import的区别?
link是HTML标签,@import是CSS提供
页面被加载时,link会同时被加载,@import得等到页面被加载完再加载
link无兼容问题,@import只在IE5以上版本才能识别
link方式的样式权重高于@import
src和href的区别?
src:把资源下载到页面中
href:超文本引用,指向资源的位置,建立与目标文件的联系
display:none、visibility:hidden和opacity:0的区别?
display:none是彻底消失,不在文档流中占位,浏览器不会解析该元素,不可点击,不可继承
visibility:hidden是视觉上消失,在文档流中占位,浏览器会解析该元素,不可点击,可继承
opacity:0是是视觉上消失,在文档流中占位,浏览器会解析该元素,可点击,不可继承
px、em、rem和vh/vw的区别?
px:绝对单位,页面按精确像素显示
em:相对单位,相对父节点字体的大小
rem:相对单位,相对根节点html字体的大小
vh/vw:用于页面视口大小布局
媒体查询?
在不改变内容的情况下,改变页面的布局以精确适应不同的设备
实现响应式布局?
媒体查询、百分比、vw/vh、rem
typeof
检测数据类型,可检测到string、number、boolean、undefined、object、function
检测一个属性是否属于某个对象,返回true或false
'属性名' in obj:自有属性或者继承属性
obj.hasOwnProperty('属性名'):自有属性
obj.propertyIsEnumerable('属性名'):自有属性且可枚举
instaceof
检测是否是构造函数的实例
undefined 与null关系
undefined继承null,但是null表示空对象,undefined表示未定义;
数组API
arr.toString() | 将数组转化为字符串 | |
arr.join("分隔符") | 将数组转化为字符串 | |
Array.from(arr) | 将类数组对象转换为一个数组 | |
Array.prototype.slice.call(childs,0); | 将字符串转换为一个数组 | |
let [...str] = 'hello'; | 将字符串转换为一个数组 | |
Array.isArray(arr) | 判断是否为数组 | |
arr.push('tom',{age:13}) | 添加最后一个元素,返回新的长度 | 改变原数组 |
arr.pop() | 删除并返回最后一个元素 | 改变原数组 |
arr.unshift([5,6,7,8],function test(){}) | 添加第一个元素,返回新的长度 | 改变原数组 |
arr.shift() | 删除并返回第一个元素 | 改变原数组 |
arr.reverse() | 颠倒顺序 | 改变原数组 |
arr.sort() | 排序 | 改变原数组 |
arr.sort(function(a,b){ }) | 按指定规则排序 | 改变原数组 |
arr.concat(arr1,arr2,arr3) | 拼接数组 | 不改变原数组 |
arr.slice(1,2) | 截取并返回新数组, 参数是索引( start end(不包含)) | 不改变原数组 |
arr.splice(1) | 删除并返回下标从1开始到结尾的数组 | 改变原数组 |
arr.splice(0,2) | 删除并返回下标从0开始长度为2的数组 | 改变原数组 |
arr.splice(2,0,'lavender') | 在下标为2的位置上添加元素,并返回空数组 | 改变原数组 |
arr.indexOf('zhangsan111') | 返回索引 | 不改变原数组 |
arr.lastIndexOf("tom") | 返回索引 | 不改变原数组 |
arr.every(function(item,index,arr){return item>12; }) | 所有元素通过检测返回true | 不改变原数组 |
arr.some(function(item,index,arr){return item>12;}) | 只要有一个元素通过检测返回true | 不改变原数组 |
arr.map(function(item,index,arr){return item.id; }) | 返回对每一项数组元素做了操作之后的一个新数组 | 不改变原数组 |
arr.filter(function(item,index,arr){return item.id; }) | 返回符合条件的元素创建的新数组 | 不改变原数组 |
arr.forEach(function(item,index,arr) { }) | 调用数组的每一个元素 没有返回值 | 不改变原数组 |
ES6数组静态方法和实例方法API扩展
Array.of():创建数组,参数:数组元素,返回值:新数组
arr.find(): 参数:回调函数 返回值:返回第一个满足条件的元素
arr.findIndex():参数:回调函数,返回值:返回满足条件的第一个元素的索引或者-1
arr.fill():修改(填充)原数组,参数:填充的数组元素,返回值:填充好的新数组
对象API
对象序列化即将对象转换为JSON字符串:JSON.stringify(obj)
反序列化即将字符串还原为对象:JSON.parse(json)
ES6对象静态API扩展
Object.assign():两个参数:复制/拷贝,三个参数:合并对象
Object.getPrototypeOf():获取原型对象
Object.setPrototypeOf():设置原型对象
Object.keys():获取属性名组成的数组,参数:目标对象
Object.values():获取属性值组成的数组,参数:目标对象
Object.entries():获取键值对(属性名和属性值)组成的数组,参数:目标对象
什么是原型?
每一个构造函数都有一个原型对象(Object.prototype),
每一个原型对象都有一个指针指向构造函数(Object.prototype.constructor)
实例都包含一个指向原型对象的指针(obj.__proto__)
this指针
在方法中,this 表示该方法所属的对象。
普通函数调用,this 表示全局对象。
如果单独使用,this 表示全局对象。
在事件中,this 指向接受事件的html元素。
箭头函数的this始终指向函数声明时所在作用域下的 this 的值
函数名.call(执行环境对象,实参列表);
函数名.apply(执行环境对象,实参列表数组);
函数名.bind(执行环境对象)(实参列表);:bind方法返回的只是一个修改过后的函数
new操作符做了什么
创建了对象---this指向这个对象---执行函数体---返回这个对象
四种模式
批量创建对象,封装创建对象的函数,提高代码复用性。
工厂模式:创建出来的对象都是Object类型,无法区分对象种类。将函数声明成全局变量解决方法空间浪费,但是会产生方法冗余问题
构造函数模式:可以区分对象种类,但方法冗余
原型模式:解决了方法冗余,所有实例共享的属性和方法,但是私有属性得不到维护
原型模式不单独使用,构造函数中什么都不放,将所有的属性和方法都放到原型对象中
组合模式:构造函数模式+原型模式
构造函数中放实例私有的属性,构造函数原型对象中放公共属性和方法
继承
构造函数继承、经典继承:在子类构造函数内调用父类构造函数
组合继承(原型继承+经典继承)
DOM0级事件和DOM2级事件的区别
DOM0级事件--不可追加事件
DOM2级事件--可追加事件
追加:addEventListener(事件类型,事件处理程序,布尔值)
true--在捕获阶段执行,false--在冒泡阶段执行
解绑:removeEventListener(事件类型,事件处理程序(具名函数))
阻止事件冒泡
event.stopPropagation()
阻止事件默认行为
event.preventDefault()
CommonJS和ES6的区别
ES6输出的是值的引用(浅拷贝),CommonJS输出的是值的拷贝/复制(深拷贝)
ES6模块是编译时输出接口,CommonJS模块是运行时加载
Symbol
表示独一无二的值---全局注册表
Symbol.for(key) :创建的的symbol 会被放入一个全局symbol 注册表中。
Symbol.keyFor():检测symbol值是否在全局注册过,返回key或者Undefined。
迭代器Iterator
Array、Map、Set、String、TypedArray、arguments、NodeList
for-of实现原理就是调用迭代器的next()方法
Set
Set类似于数组,但是成员的值都是唯一的,没有重复的值。
Map
Map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串。
数组去重
使用双层for循环+splice()进行数组去重(删除数组中重复的元素)
利用indexOf()+push()进行数组去重(在新数组中添加新数组查找不到的元素)
利用includes()+push()进行数组去重(在新数组中添加新数组不包含的元素)
利用set进行数组去重(set成员唯一的,数组转set再转数组)
Promise
回调函数的两个参数分别是resolve和reject
Promise的三种状态pending(进行中)、fulfilled(已成功)和rejected(已失败)