元旦匆匆而过,2020年的春节又接踵而来,你们除了忙的提着裤子加班、年末冲冲冲外,还有着对于明年的迷茫和期待!2019年有多少苦涩心酸,2020年就有更多幸福美好,加油,奥利给!怀着一颗积极向上的心,来面对将来每一天的挑战!javascript
所谓“兵马未动,粮草先行”,咱们打响明天的战役也须要精神食粮来作后勤保障才是。在此我整理了多位从业者和我在2019年末至2020年初的一厂面试精选题,但愿对磨砺锋芒、奋发向上的小伙伴有所帮助,祝你早日剑指大厂,扬帆起航,奥利给!php
盒子模型就是 元素在网页中的实际占位,有两种:标准盒子模型和IE盒子模型css
标准(W3C)盒子模型:内容content+填充padding+边框border+边界margin宽高指的是 content 的宽高html
低版本IE盒子模型:内容(content+padding+border)+ 边界margin,宽高指的是content+padding+border 部分的宽高前端
/* 标准模型 */ box-sizing:content-box; /*IE模型*/ box-sizing:border-box;
父子元素、兄弟元素,当有外边距时,会取其中一个边距的最大值,做为实际的边距。
空元素的有上下边距时,也会取其中更大的一个边距值,做为实际的边距。
这就是边距重叠。vue
BFC:
概念:块级格式化上下文
原理:java
垂直方向的padding: 在css中,padding-top或padding-bottom的百分比值是根据容器的width来计算的。node
.wrap{ position: relative; height: 0; //容器的height设置为0 width: 100%; padding-top: 75%; //100%*3/4 } .wrap > *{ position: absolute;//容器的内容的全部元素absolute,然子元素内容都将被padding挤出容器 left: 0; top: 0; width: 100%; height: 100%; }
+ **padding & calc()**: 跟第一种方法原理相同 ```css padding-top: calc(100%*9/16);
width:100vw; height:calc(100vw*3/4)
优先级就近原则,同权重状况下样式定义最近者为准react
!important>id >class>tagwebpack
important比内联优先级高
元素选择符的权值:元素标签(派生选择器):1,class选择符:10,id选择符:100,内联样式权值最大,为1000
1、对于行内元素:
text-align:center;
2、对于肯定宽度的块级元素:
(1)margin和width实现水平居中
经常使用(前提:已设置width值):margin-left:auto; margin-right:auto;
(2)绝对定位和margin-left: -(宽度值/2)实现水平居中
固定宽度块级元素水平居中,经过使用绝对定位,以及设置元素margin-left为其宽度的一半
.content{ width: 200px; position: absolute; left: 50%; margin-left: -100px; // 该元素宽度的一半,即100px background-color: aqua; }
(3)position:absolute + (left=0+top=0+right=0+bottom=0) + margin:auto
.content{ position: absolute; width: 200px; top: 0; right: 0; bottom: 0; left: 0; margin: auto; }
3、对于未知宽度的块级元素:
(1)table标签配合margin左右auto实现水平居中
使用table标签(或直接将块级元素设值为display:table),再经过给该标签添加左右margin为auto
(2)inline-block实现水平居中方法
display:inline-block;(或display:inline)和text-align:center;实现水平居中
存在问题:需额外处理inline-block的浏览器兼容性(解决inline-block元素的空白间距)
(3)绝对定位实现水平居中
绝对定位+transform,translateX能够移动本省元素的50%
.content{ position: absolute; left: 50%; transform: translateX(-50%); /* 移动元素自己50% */ background: aqua; }
(4)相对定位实现水平居中
用float或者display把父元素变成行内块状元素
.contentParent{ display: inline-block; /* 把父元素转化为行内块状元素 */ /*float: left; 把父元素转化为行内块状元素 */ position: relative; left: 50%; } /*目标元素*/ .content{ position: relative; right: 50%; background-color:aqua; }
(5)CSS3的flex实现水平居中方法,法一
.contentParent{ display: flex; flex-direction: column; } .content{ align-self:center; }
(6)CSS3的flex实现水平居中方法,法二
.contentParent{ display: flex; } .content{ margin: auto; }
(7)CSS3的fit-content配合左右margin为auto实现水平居中方法
.content{ width: fit-content; margin-left: auto; margin-right: auto; }
参考连接 https://blog.csdn.net/dengdongxia/article/details/80297116
该布局模型的目的是提供一种更加高效的方式来对容器中的条目进行布局、对齐和分配空间。在传统的布局方式中,block 布局是把块在垂直方向从上到下依次排列的;而 inline 布局则是在水平方向来排列。弹性盒布局并无这样内在的方向限制,能够由开发人员自由操做。flexbox设置父元素的display
属性为flex
,则子元素都变成flex item
,由此能够控制子元素的排列方式、尺寸、间距等;
试用场景:弹性布局适合于移动前端开发,在Android和ios上也完美支持。
左右边框设置为透明,长度为底部边框的一半。左右边框长度必须设置,不设置则只有底部一条边框,是不能展现的。
{width: 0; height: 0; border-top: 40px solid transparent; border-left: 40px solid transparent; border-right: 40px solid transparent; border-bottom: 40px solid #ff0000;}
<img class="circle" src="001.jpg" width="400" height="400"/> //infinite 表示动画无限次播放 linear表示动画从头至尾的速度是相同的 .circle{ animation: myRotation 5s linear infinite; } @keyframes myRotation { from {transform: rotate(0deg);} to {transform: rotate(360deg);} }
inline默认。此元素会被显示为内联元素,元素先后没有换行符。
block此元素将显示为块级元素,此元素先后会带有换行符。
none此元素不会被显示(隐藏)。
inline-block行内块元素。(CSS2.1 新增的值)
list-item此元素会做为列表显示。
table此元素会做为块级表格来显示(相似table),表格先后带有换行符
absolute
生成绝对定位的元素,相对于 static 定位之外的第一个父元素进行定位。
元素的位置经过 "left", "top", "right" 以及 "bottom" 属性进行规定。
fixed
生成固定定位的元素,相对于浏览器窗口进行定位。(老IE不支持)
元素的位置经过 "left", "top", "right" 以及 "bottom" 属性进行规定。
relative
生成相对定位的元素,相对于其正常位置进行定位,不脱离文档流。
所以,"left:20" 会向元素的 LEFT 位置添加 20 像素。
static默认值。
没有定位,元素出如今正常的文档流中(忽略 top, bottom, left, right 或者 z-index 声明)。inherit规定应该从父元素继承 position 属性的值。
由于浏览器的兼容问题,不一样浏览器对有些标签的默认值是不一样的,若是没对CSS初始化每每会出现浏览器之间的页面显示差别。
在布局方面新增了flex布局;
在选择器方面新增了例如:first-of-type,nth-child等选择器;
在盒模型方面添加了box-sizing来改变盒模型,
在动画方面增长了animation、2d变换、3d变换等。在颜色方面添加透明、rgba等,
在字体方面容许嵌入字体和设置字体阴影,同时固然也有盒子的阴影,
媒体查询。为不一样设备基于它们的能力定义不一样的样式。
@media screen and (min-width:960px) and (max-width:1200px){ body{ background:yellow; } }
元素的显示隐藏方法不少,不一样方法的在不一样的场景下页面效果不一,对页面的性能也有不一样的影响。
元素隐藏方法总结:
若是但愿元素不可见、不占据空间、资源会加载、DOM 可访问: display: none
;
若是但愿元素不可见、不能点击、但占据空间、资源会加载,可使用: visibility: hidden
;
若是但愿元素不可见、不占据空间、显隐时能够又transition
淡入淡出效果
div{ position: absolute; visibility: hidden; opacity: 0; transition: opacity .5s linear; background: cyan; } div.active{ visibility: visible; opacity: 1; }
这里使用visibility: hidden
而不是display: none
,是由于display: none
会影响css3的transition
过渡效果。 可是display: none
并不会影响cssanimation
动画的效果。
若是但愿元素不可见、能够点击、占据空间,可使用: opacity: 0
;
若是但愿元素不可见、能够点击、不占据空间,可使用: opacity: 0; position: absolute;
;
若是但愿元素不可见、不能点击、占据空间,可使用: position: relative; z-index: -1;
;
若是但愿元素不可见、不能点击、不占据空间,可使用: position: absolute ; z-index: -1;
display: none
与visibility: hidden
的区别display: none
的元素不占据任何空间,visibility: hidden
的元素空间保留;display: none
会影响css3的transition
过渡效果,visibility: hidden
不会;display: none
隐藏产生重绘 ( repaint ) 和回流 ( relfow ),visibility: hidden
只会触发重绘;display: none
的节点和子孙节点元素全都不可见,visibility: hidden
的节点的子孙节点元素能够设置 visibility: visible
显示。visibility: hidden
属性值具备继承性,因此子孙元素默认继承了hidden
而隐藏,可是当子孙元素重置为visibility: visible
就不会被隐藏。意外的全局变量引发的内存泄漏
闭包引发的内存泄漏
未清除 dom 元素的引用的内存泄漏
循环引用引发的内存泄漏
被遗忘的计时器或回调引发的内存泄漏
const wm = new WeakMap(); const element = document.getElementById('example'); wm.set(element, 'some information'); wm.get(element) // "some information"
先新建一个 Weakmap 实例。而后,将一个 DOM 节点做为键名存入该实例,并将一些附加信息做为键值,一块儿存放在 WeakMap 里面。这时,WeakMap 里面对element的引用就是弱引用,不会被计入垃圾回收机制。
也就是说,DOM 节点对象的引用计数是1,而不是2。这时,一旦消除对该节点的引用,它占用的内存就会被垃圾回收机制释放。Weakmap 保存的这个键值对,也会自动消失。
// 该段代码会启动一个针对“example.php”的GET同步请求。 xhr.open("get", "example.php", false)
readyState | 对应常量 | 描述 |
---|---|---|
0(未初始化) | xhr.UNSENT | 请求已创建, 但未初始化(此时未调用open方法) |
1(初始化) | xhr.OPENED | 请求已创建, 但未发送 (已调用open方法, 但未调用send方法) |
2(发送数据) | xhr.HEADERS_RECEIVED | 请求已发送 (send方法已调用, 已收到响应头) |
3(数据发送中) | xhr.LOADING | 请求处理中, 因响应内容不全, 这时经过responseBody和responseText获取可能会出现错误 |
4(完成) | xhr.DONE | 数据接收完毕, 此时能够经过responseBody和responseText获取完整的响应数据 |
//promise 实现ajax function ajax(method, url, data) { var request = new XMLHttpRequest(); return new Promise(function (resolve, reject) { request.onreadystatechange = function () { if (request.readyState === 4) { if (request.status === 200) { resolve(request.responseText); } else { reject(request.status); } } }; request.open(method, url); request.send(data); }); } ajax('GET', '/api/categories').then(function (text) { // 若是AJAX成功,得到响应内容 log.innerText = text; }).catch(function (status) { // 若是AJAX失败,得到响应代码 log.innerText = 'ERROR: ' + status; });
function instanceOf(left,right) { let proto = left.__proto__; let prototype = right.prototype while(true) { if(proto === null) return false; if(proto === prototype) return true; proto = proto.__proto__; } }
Object.prototype.toString.call('') ; // [object String] Object.prototype.toString.call(1) ; // [object Number] Object.prototype.toString.call(true) ; // [object Boolean] Object.prototype.toString.call(Symbol()); //[object Symbol] 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 的引用
const config = { root: null, // 默认指向浏览器的视口,但能够是任意DOM元素 rootMargin: '0px', // 计算交叉时,root边界盒的偏移量 threshold: 0.5 // 监听对象的交叉区域与边界区域的比率 } let observer = new IntersectionObserver(fucntion(entries){ // ... }, config) new IntersectionObserver(function(entries, self))
<img src="default.jpg" data-src="www.example.com/1.jpg">
const images = document.querySelectorAll('[data-src]') const config = { rootMargin: '0px', threshold: 0 }; let observer = new IntersectionObserver((entries, self)=>{ entries.forEach(entry => { if(entry.isIntersecting){ // 加载图像 preloadImage(entry.target); // 解除观察 self.unobserve(entry.target) } }) }, config) images.forEach(image => { observer.observe(image); }); function preloadImage(img) { const src = img.dataset.src if (!src) { return; } img.src = src; }
参考: 实现图片懒加载
var debounce = function(delay, cb) { var timer; return function() { if (timer) clearTimeout(timer); timer = setTimeout(function() { cb(); }, delay); } }
var throttle = function(delay, cb) { var startTime = Date.now(); return function() { var currTime = Date.now(); if (currTime - startTime > delay) { cb(); startTime = currTime; } } }
//使用cloneNode,可是在元素上绑定的事件不会拷贝 function clone(origin) { return Object.assign({},origin); } //实现了对原始对象的克隆,可是只能克隆原始对象自身的值,不能克隆她继承的值,若是想要保持继承链,能够采用以下方法: function clone(origin) { let originProto=Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto),origin); }
<script src="path/to/myModule.js" defer></script> <script src="path/to/myModule.js" async></script>
const foo=Object.freeze({}); foo.prop=123; console.log(foo.prop);//混杂模式undefined,不起做用
var proxy = new Proxy({}, { get: function(target, property) { return 35; } }); let obj = Object.create(proxy); obj.time // 35
const curry = (fn, currArgs=[]) => { return function() { let args = Array.from(arguments); [].push.apply(args,currArgs); if (args.length < fn.length) { return curry.call(this,fn,...args); } return fn.apply(this,args); } }
d3经过svg绘制图形,能够自定义事件。svg不依赖分辨率,继续xml绘制图形,能够操做dom。支持事件处理器,复杂度高,会减慢页面的渲染速度。
echarts经过canvas来绘制图形,用户经过配置 options 参数,就可很容易绘制指定图表。canvas依赖分辨率,基于js绘制图形,不支持事件处理,能以png或者jpg的格式保存图片。
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
(1)Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地获得高效更新。
(2)改变 store 中的状态的惟一途径就是显式地提交 (commit) mutation。这样使得咱们能够方便地跟踪每个状态的变化。
vuex的store有State、 Getter、Mutation 、Action、 Module五种属性;
<body> <div id="app"> <input type="text" id="txt"> <p id="show"></p> </div> </body> <script type="text/javascript"> var obj = {} Object.defineProperty(obj, 'txt', { get: function () { return obj }, set: function (newValue) { document.getElementById('txt').value = newValue document.getElementById('show').innerHTML = newValue } }) document.addEventListener('keyup', function (e) { obj.txt = e.target.value }) </script>
父组件经过props属性与子组件通讯
父组件:
<parent> <single-voice ref="singleVoiceRef" :parent-to-child="singleVoiceData"/> </parent> data(){ return { singleVoiceData:'来自父组件的数据' } }
// 父组件调用子组件中的方法,将值传递给子组件
CSSmethods:{` `this.$refs.singleVoiceRef.openSingleVoice(this.singleVoiceData)` `}`
子组件经过props来接受数据
props: {parentToChild: {type: String,required: true}},methods:{openSingleVoice(SingleVoice) {console.log(SingleVoice)}}
子组件向父组件传值
vue2.0只容许单向数据传递,咱们经过出发事件来改变组件的数据
子组件代码:
<template> <div @click="open"></div> </template> methods: { open() { this.$emit('showbox','the msg'); //触发showbox方法,'the msg'为向父组件传递的数据 } }
父组件代码:
<child @showbox="toshow" :msg="msg"></child> //监听子组件触发的showbox事件,而后调用toshow方法 methods: { toshow(msg) { this.msg = msg; } }
兄弟组件之间的通讯
咱们能够实例化一个vue实例,至关于一个第三方
eventVue.$emit(‘function1’,value) eventVue.$on(‘function1’, (message) => { // 箭头函数接收 })
建立一个公共桥梁 eventVue.js
import Vue from 'vue' export default new Vue()
兄弟组件内引入 eventVue.js
兄弟组件一
import eventVue from './eventVue.js' export default { methods: { // 点击通信录与员工进行语音聊天 handleChatStaff(staffInfo) { console.log(staffInfo) this.staffInfo = staffInfo eventVue.$emit('updateChatList', this.staffInfo) }, } }
兄弟组件二
import eventVue from './eventVue.js' export default { created() { this.updateList() }, methods: { updateList() { eventVue.$on('updateChatList', (message) => { // 与phoneBook组件通讯 console.log(message) this.updateChatListEvent() }) }, // 更新聊天列表 updateChatListEvent() {}, }
其余参考地址 :
https://www.imooc.com/article/68394?block_id=tuijian_wz
http://www.javashuo.com/article/p-dtiquxjs-mz.html
参考地址:
http://www.javashuo.com/article/p-hkoypzim-mz.html
https://www.jianshu.com/p/2d47396c775c
Vue 实例有一个完整的生命周期,也就是从开始建立、初始化数据、编译模版、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,咱们称这是 Vue 的生命周期。
beforeCreate 组件实例被建立之初,组件的属性生效以前
created 组件实例已经彻底建立,属性也绑定,但真实 dom 尚未生成,$el 还不可用
beforeMount 在挂载开始以前被调用:相关的 render 函数首次被调用 mounted el 被新建立的 vm.$el 替换,并挂载到实例上去以后调用该钩子
beforeUpdate 组件数据更新以前调用,发生在虚拟 DOM 打补丁以前
update 组件数据更新以后
activited keep-alive 专属,组件被激活时调用
deactivated keep-alive 专属,组件被销毁时调用
beforeDestory 组件销毁前调用
destoryed 组件销毁后调用
好比有父组件 Parent 和子组件 Child,若是父组件监听到子组件挂载 mounted 就作一些逻辑处理,能够经过如下写法实现:
// Parent.vue <Child @mounted="doSomething"/> // Child.vue mounted() { this.$emit("mounted"); } 复制代码
以上须要手动经过 $emit 触发父组件的事件,更简单的方式能够在父组件引用子组件时经过 @hook 来监听便可,以下所示:
// Parent.vue <Child @hook:mounted="doSomething" ></Child> doSomething() { console.log('父组件监听到 mounted 钩子函数 ...'); }, // Child.vue mounted(){ console.log('子组件触发 mounted 钩子函数 ...'); }, // 以上输出顺序为: // 子组件触发 mounted 钩子函数 ... // 父组件监听到 mounted 钩子函数 ... 复制代码
固然 @hook 方法不只仅是能够监听 mounted,其它的生命周期事件,例如:created,updated 等均可以监听。
Vue 组件间通讯是面试常考的知识点之一,这题有点相似于开放题,你回答出越多方法固然越加分,代表你对 Vue 掌握的越熟练。Vue 组件间通讯只要指如下 3 类通讯:父子组件通讯、隔代组件通讯、兄弟组件通讯,下面咱们分别介绍每种通讯方式且会说明此种方法可适用于哪类组件间通讯。
(1)props / $emit
适用 父子组件通讯
这种方法是 Vue 组件的基础,相信大部分同窗耳闻能详,因此此处就不举例展开介绍。
(2)ref
与 $parent / $children
适用 父子组件通讯
ref
:若是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;若是用在子组件上,引用就指向组件实例$parent
/ $children
:访问父 / 子实例(3)EventBus ($emit / $on)
适用于 父子、隔代、兄弟组件通讯
这种方法经过一个空的 Vue 实例做为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通讯,包括父子、隔代、兄弟组件。
(4)$attrs
/$listeners
适用于 隔代组件通讯
$attrs
:包含了父做用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含全部父做用域的绑定 ( class 和 style 除外 ),而且能够经过 v-bind="$attrs"
传入内部组件。一般配合 inheritAttrs 选项一块儿使用。$listeners
:包含了父做用域中的 (不含 .native 修饰器的) v-on 事件监听器。它能够经过 v-on="$listeners"
传入内部组件(5)provide / inject
适用于 隔代组件通讯
祖先组件中经过 provider 来提供变量,而后在子孙组件中经过 inject 来注入变量。 provide / inject API 主要解决了跨级组件间的通讯问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间创建了一种主动提供与依赖注入的关系。
(6)Vuex 适用于 父子、隔代、兄弟组件通讯
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。
(1)代码层面的优化**
(2)Webpack 层面的优化
(3)基础的 Web 技术的优化
与angularjs的区别:
1****、Angular.js的学习成本高,好比增长了Dependency Injection特性,而Vue.js自己提供的API都比较简单、直观。
2****、在性能上,Angular.js依赖对数据作脏检查,因此watcher越多越慢。
3****、Vue.js使用基于依赖追踪的观察而且使用异步队列更新。全部的数据都是独立出发的。
对于庞大的应用来讲,这个优化差别仍是比较明显的。
与reactjs的区别:
React 依赖Virtual DOM,而Vue.js使用的是DOM模板。React采用的Virtual DOM会对渲染出来的结果作脏检查。
Vue.js在模板中提供了指令,过滤器等,能够很是方便,快捷地操做Virtual DOM
包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免从新渲染;
使用:简单页面时
缓存:
不缓存:
使用:复杂项目时
路由字典中定义{path:’/detail’,meta:{keepAlive:false/true}} 是否缓存
根目录中:
css的预编译。
使用步骤:
第一步:用npm 下三个loader(sass-loader、css-loader、node-sass)
第二步:在build目录找到webpack.base.config.js,在那个extends属性中加一个拓展.scss
第三步:仍是在同一个文件,配置一个module属性
第四步:而后在组件的style标签加上lang属性 ,例如:lang=”scss”
有哪几大特性:
一、能够用变量,例如($变量名称=值);
二、能够用混合器,例如:定义了字体的混合器
@mixin font-dpr($font-size){ $font:$font-size/2; font-size: $font; [data-dpr="2"] & { font-size: $font+2px;} [data-dpr="3"] & { font-size: $font+4px;} }
使用方法以下
.div{ @include font-dpr(24px); }
三、能够嵌套
<body> <div id="app"> <input type="text" id="txt"> <p id="show"></p> </div> </body> <script type="text/javascript"> var obj = {} Object.defineProperty(obj, 'txt', { get: function () { return obj }, set: function (newValue) { document.getElementById('txt').value = newValue document.getElementById('show').innerHTML = newValue } }) document.addEventListener('keyup', function (e) { obj.txt = e.target.value }) </script>
框架的好处:
组件化: 其中以 React 的组件化最为完全,甚至能够到函数级别的原子组件,高度的组件化能够是咱们的工程易于维护、易于组合拓展。
自然分层: JQuery 时代的代码大部分状况下是面条代码,耦合严重,现代框架无论是 MVC、MVP仍是MVVM 模式都能帮助咱们进行分层,代码解耦更易于读写。
生态: 如今主流前端框架都自带生态,无论是数据流管理架构仍是 UI 库都有成熟的解决方案。
开发效率: 现代前端框架都默认自动更新DOM,而非咱们手动操做,解放了开发者的手动DOM成本,提升开发效率,从根本上解决了UI 与状态同步问题.
虚拟DOM的优劣如何?
优势:
保证性能下限: 虚拟DOM能够通过diff找出最小差别,而后批量进行patch,这种操做虽然比不上手动优化,可是比起粗暴的DOM操做性能要好不少,所以虚拟DOM能够保证性能下限
无需手动操做DOM: 虚拟DOM的diff和patch都是在一次更新中自动进行的,咱们无需手动操做DOM,极大提升开发效率
跨平台: 虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM能够进行更方便地跨平台操做,例如服务器渲染、移动端开发等等
缺点:
没法进行极致优化: 在一些性能要求极高的应用中虚拟DOM没法进行针对性的极致优化,好比VScode采用直接手动操做DOM的方式进行极端的性能优化
虚拟dom至关于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操做,从而提升性能。虚拟DOM本质上是JavaScript对象,是对真实DOM的抽象,状态变动时,记录新树和旧树的差别,最后把差别更新到真正的dom中
具体实现步骤以下:
1.用 JavaScript 对象结构表示 DOM 树的结构;而后用这个树构建一个真正的 DOM 树,插到文档当中;
2.当状态变动的时候,从新构造一棵新的对象树。而后用新的树和旧的树进行比较,记录两棵树差别;
把2所记录的差别应用到步骤1所构建的真正的DOM树上,视图就更新了
组件加载以前,组件加载完成,以及组件更新数据,组件销毁。触发的一系列的方法 ,这就是组件的生命周期函数
一、初始化阶段:
getDefaultProps:获取实例的默认属性
getInitialState:获取每一个实例的初始化状态
componentWillMount:组件即将被装载、渲染到页面上
render:组件在这里生成虚拟的DOM节点
componentDidMount:组件真正在被装载以后
二、运行中状态:
componentWillReceiveProps:组件将要接收到属性的时候调用
shouldComponentUpdate:组件接受到新属性或者新状态的时候(能够返回false,接收数据后不更新,阻止render调用,后面的函数不会被继续执行了)
componentWillUpdate:组件即将更新不能修改属性和状态
render:组件从新描绘
componentDidUpdate:组件已经更新
三、销毁阶段:
componentWillUnmount:组件即将销毁
必须记住的生命周期函数:
*加载的时候:componentWillMount、 render 、componentDidMount(dom操做) 更新的时候:componentWillUpdate、render、componentDidUpdate *销毁的时候: componentWillUnmount
diff算法做为Virtual DOM的加速器,其算法的改进优化是React整个界面渲染的基础和性能的保障,同时也是React源码中最神秘的,最难以想象的部分
传统diff算法经过循环递归对比差别,算法复杂度为O(n3)。react diff算法制定了三条策略,将算法复杂度从 O(n3)下降到O(n)。
ID
来区分。针对这三个策略,react diff实施的具体策略是:
因为react中性能主要耗费在于update阶段的diff算法,所以性能优化也主要针对diff算法。
1.减小diff算法触发次数
A、 setState机制在正常运行时,因为批更新策略,已经下降了update过程的触发次数。
所以,setState优化主要在于非批更新阶段中(timeout/Promise回调),减小setState的触发次数。
常见的业务场景即处理接口回调时,不管数据处理多么复杂,保证最后只调用一次setState。
B、父组件的render必然会触发子组件进入update阶段(不管props是否更新)。此时最经常使用的优化方案即为shouldComponentUpdate方法。最多见的方式为进行this.props和this.state的浅比较来判断组件是否须要更新。或者直接使用PureComponent,原理一致。须要注意的是,父组件的render函数若是写的不规范,将会致使上述的策略失效。
C、使用shouldComponentUpdate钩子,根据具体的业务状态,减小没必要要的props变化致使的渲染。如一个不用于渲染的props致使的update。
另外, 也要尽可能避免在shouldComponentUpdate 中作一些比较复杂的操做, 好比超大数据的pick操做等。
合理设计state,不须要渲染的state,尽可能使用实例成员变量。
二、正确使用diff算法
不使用跨层级移动节点的操做。
对于条件渲染多个节点时,尽可能采用隐藏等方式切换节点,而不是替换节点。
尽可能避免将后面的子节点移动到前面的操做,当节点数量较多时,会产生必定的性能问题。
性能检测工具
React官方提供的:React.addons.Perf
React是facebook搞出来的一个轻量级的组件库,用于解决前端视图层的一些问题,就是MVC中V层的问题,它内部的Instagram网站就是用React搭建的。
解决了三个问题: 1.组件复用问题, 2.性能问题,3.兼容性问题:
React 会建立一个虚拟 DOM(virtual DOM)。当一个组件中的状态改变时,React 首先会经过 "diffing" 算法来标记虚拟 DOM 中的改变,第二步是调节(reconciliation),会用 diff 的结果来更新 DOM。
优势:
1.只需查看 render 函数就会很容易知道一个组件是如何被渲染的
2.JSX 的引入,使得组件的代码更加可读,也更容易看懂组件的布局,或者组件之间是如何互相引用的
3.支持服务端渲染,这能够改进 SEO 和性能
4.易于测试
5.React 只关注 View 层,因此能够和其它任何框架(如Backbone.js, Angular.js)一块儿使用
Angular是一个成熟的MVC框架,带有不少特定的特性,好比服务、指令、模板、模块、解析器等等。React是一个很是轻量级的库,它只关注MVC的视图部分。
Angular遵循两个方向的数据流,而React遵循从上到下的单向数据流。React在开发特性时给了开发人员很大的自由,例如,调用API的方式、路由等等。咱们不须要包括路由器库,除非咱们须要它在咱们的项目。
AngularJS是为了克服HTML在构建应用上的不足而设计的。 AngularJS有着诸多特性,最为核心的是:
Angular 在 scope 模型上设置了一个监听队列,用来监听数据变化并更新 view 。每次绑定一个东西到 view 上时 AngularJS 就会往 $watch 队列里插入一条 $watch ,用来检测它监视的 model 里是否有变化的东西。当浏览器接收到能够被 angular context 处理的事件时, $digest 循环就会触发,遍历全部的 $watch ,最后更新 dom。
一、每一个双向绑定的元素都有一个watcher
二、在某些事件发生的时候,调用digest脏数据检测。
这些事件有:表单元素内容变化、Ajax请求响应、点击按钮执行的函数等。
三、脏数据检测会检测rootscope下全部被watcher的元素。
$digest
函数就是脏数据监测
单页 Web 应用 (single-page application 简称为 SPA) 是一种特殊的 Web 应用。它将全部的活动局限于一个Web页面中,仅在该Web页面初始化时加载相应的HTML、JavaScript 和 CSS。一旦页面加载完成了,SPA不会由于用户的操做而进行页面的从新加载或跳转。取而代之的是利用 JavaScript 动态的变换HTML的内容,从而实现UI与用户的交互。因为避免了页面的从新加载,SPA 能够提供较为流畅的用户体验。
一、优势:
1).良好的交互体验
用户不须要从新刷新页面,获取数据也是经过Ajax异步获取,页面显示流畅。
2).良好的先后端工做分离模式
单页Web应用能够和RESTful规约一块儿使用,经过REST API提供接口数据,并使用Ajax异步获取,这样有助于分离客户端和服务器端工做。更进一步,能够在客户端也能够分解为静态页面和页面交互两个部分。
3).减轻服务器压力
服务器只用出数据就能够,不用管展现逻辑和页面合成,吞吐能力会提升几倍;
4).共用一套后端程序代码
不用修改后端程序代码就能够同时用于Web界面、手机、平板等多种客户端;
二、缺点:
1).SEO难度较高
因为全部的内容都在一个页面中动态替换显示,因此在SEO上其有着自然的弱势,因此若是你的站点对SEO很看重,且要用单页应用,那么就作些静态页面给搜索引擎用吧。
2).前进、后退管理
因为单页Web应用在一个页面中显示全部的内容,因此不能使用浏览器的前进后退功能,全部的页面切换须要本身创建堆栈管理,固然此问题也有解决方案,好比利用URI中的散列+iframe实现。
3).初次加载耗时多
为实现单页Web应用功能及显示效果,须要在加载页面的时候将JavaScript、CSS统一加载,部分页面能够在须要的时候加载。因此必须对JavaScript及CSS代码进行合并压缩处理,若是使用第三方库,建议使用一些大公司的CDN,所以带宽的消耗是必然的。
还有2件事拜托你们
一:求赞 求收藏 求分享 求留言,让更多的人看到这篇内容
二:欢迎添加个人我的微信
备注“资料”, 300多篇原创技术文章,海量的视频资料便可得到
备注“加群”,我会拉你进技术交流群,群里大牛学霸具在,哪怕您作个潜水鱼也会学到不少东西
金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)上
金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)中
金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)下
2020 前端面试 | “HTML + CSS + JS”专题