元旦匆匆而過,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」專題