1.關於jsjavascript
(1)宏任務和微任務:css
宏任務分類:總體代碼的script setTimeout setInterval requrestAnimationFramehtml
微任務分類:new promise().then(回調) process.nextTick(在node運行環境中優先級高於promise())前端
實例:vue
console.log('開始');
setTimeout(function() { console.log('setTimeout'); }) new Promise(function(resolve) { console.log('promise'); }).then(function() { console.log('then'); }) console.log('console');
運行結果: 開始 promise console then setTimetoutjava
解釋: 1 執行一個宏任務(棧中沒有,就從事件隊列中獲取)。node
2執行過程當中若是遇到微任務,就將它添加到微任務隊列中。react
3宏任務執行完畢後,就當即執行當前微任務隊列中全部的微任務(依次執行)。webpack
4.當前宏任務執行完畢,開始檢查渲染,而後GUI 線程接管渲染。css3
5.渲染完畢後,js線程繼續接管,開始完成下一共宏任務(從事件隊列中獲取)。
(2)事件循環機制:
1.同步和異步任務分別進入不一樣的執行」場所「,同步的進入主線程,異步的進入Event 列表並註冊函數。
2.當指定的事情完成時,Event 列表會將這個函數移入 event 隊列
3.當棧中代碼執行完畢,執行棧中的任務爲空時,就會讀取任務隊列中的事件,去執行對應的回調。
4.如此循環,造成js的事件循環機制
(3)如何理解閉包 ,閉包的使用場景:
閉包就是函數調用本身做用域外的變量,或者說成調用做用域鏈上的變量,這種引用就叫閉包。 閉包的做用,改變變量的做用域。
應用場景:好比 一個變量觸發某個事件的時候會改變值,而另外一個函數根據這個值作響應變化。
(4)es5繼承和es6繼承,區別:
1.ES5先建立子類,在實例化父類並添加到子類this中
2.ES6先建立父類,在實例化子集中經過調用super方法訪問父級後,在經過修改this實現繼承
es5繼承:實質是先建立子類元素child的實例對象,而後再把父類元素parent的原型對象中的屬性賦值給了子類元素chid的實例對象裏面,從而實現繼承。
1.原型繼承 :利用call和apply繼承this上面的屬性和方法
2.原型鏈繼承:將父類的實例做爲子類的原型
3.組合繼承:利用call apply 繼承屬性
利用原型鏈繼承方法
es6繼承:es6中採用extend繼承
繼承用extends,當繼承後須要用super()來接收父類的constructor構造函數,否在報錯,當new一個子類的時候先把參數傳入子類構造函數再經過super()講父類的構造函數引入,就能夠調用父類。
(5)垃圾回收:
Js具備自動垃圾回收機制。垃圾收集器會按照固定的時間間隔週期性的執行。
標記清除:工做原理:是當變量進入環境時,將這個變量標記爲「進入環境」。當變量離開環境時,則將其標記爲「離開環境」。標記「離開環境」的就回收內存。
引用計數 :工做原理:跟蹤記錄每一個值被引用的次數。
(6)什麼狀況下會發生內存泄漏:
1. 意外的全局變量引發的內存泄漏。
緣由:全局變量,不會被回收。
解決:使用嚴格模式避免。
2. 閉包引發的內存泄漏
緣由:閉包能夠維持函數內局部變量,使其得不到釋放。
解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用。
3. 沒有清理的DOM元素引用
緣由:雖然別的地方刪除了,可是對象中還存在對dom的引用
解決:手動刪除。
4. 被遺忘的定時器或者回調
緣由:定時器中有dom的引用,即便dom刪除了,可是定時器還在,因此內存中仍是有這個dom。
解決:手動刪除定時器和dom。
5. 子元素存在引用引發的內存泄漏
緣由:div中的ul li 獲得這個div,會間接引用某個獲得的li,那麼此時由於div間接引用li,即便li被清空,也仍是在內存中,而且只要li不被刪除,他的父元素都不會被刪除。
解決:手動刪除清空。
(7)深拷貝和淺拷貝:
淺拷貝:淺拷貝就是拷貝了一層,除了對象時拷貝的引用類型,其餘都是直接值傳遞,有本身的內存空間的。
深拷貝:深拷貝時拷貝多層,即便是嵌套了對象,也會拷貝出來。
深拷貝的實現方式:
1.對象只有一層的話可使用上面的:手動複製:把一個對象的屬性複製給另外一個對象的屬性
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
3.用把對象轉成字符串,再用把字符串轉成新的對象。Object.assign()函數是深拷貝 ,不然是淺拷貝。
2.JSON.stringifyJSON.parse
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1);
// { body: { a: 10 } } <-- 沒被改到
console.log(obj2);
// { body: { a: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.body === obj2.body);
可是這種方法也有很多壞處,譬如它會拋棄對象的constructor。也就是深拷貝以後,無論這個對象原來的構造函數是什麼,在深拷貝以後都會變成Object。
也就是說,只有能夠轉成JSON格式的對象才能夠這樣用,像function沒辦法轉成JSON。
4.遞歸
5.數組的化 .splice(0)也是深拷貝。
(8)變量提高,函數的提高:
1.變量聲明的提高:經過var定義(聲明)的變量,在定義語句以前就能夠訪問到值:undefined
2.函數聲明的提高:經過function(聲明)的函數,在以前就能夠直接調用值:函數定義(對象)
(9)call,apply,bind 區別:
相同點:
一、都是用來改變函數的this對象的指向的。
二、第一個參數都是this要指向的對象。
三、均可以利用後續參數傳參。
1.call的語法:函數名.call(obj,"參數1",」參數2「);
2. apply的語法:函數名.apply(obj,[參數1,參數2,參數3……]);
3.bind 的語法:函數名bind(obj,"參數1",」參數2「)();
(10)js設計模式,應用場景:
1.單例模式:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點
應用場景: 一個redux只有一個store 就是單列模式。
2.策略模式:定義一系列的算法,把它們一個個封裝起來,而且使它們能夠相互替換
應用場景: 表單驗證方法
優勢
能夠有效地避免多重條件語句,將一系列方法封裝起來也更直觀,利於維護
缺點
每每策略集會比較多,咱們須要事先就瞭解定義好全部的狀況
3.代理模式:爲一個對象提供一個代用品或佔位符,以便控制對它的訪問
代理模式主要有三種:保護代理、虛擬代理、緩存代理
保護代理應用場景:保護代理主要實現了訪問主體得限制行爲,以過濾字符做爲簡單得例子
虛擬代理模式應用場景:函數得節流,是虛擬代理。
緩存代理:爲一些開銷大得運算結果提供暫時得緩存,提高效率。 緩存加法操做。
4.迭代器模式:迭代器模式是指提供一種方法順序訪問一個聚合對象中的各個元素,而又不須要暴露該對象的內部表示
應用場景:map foreach
5.發佈-訂閱模式:也是觀察者模式,定義了對象間一種一對多得依賴關係,當一個對象得狀態發生改變時,全部依賴於它得對象都將獲得通知。
應用場景:redux就是訂閱者模式,事件監聽也訂閱者模式。組件自動發現props或者state變化自動更新,就是觀察者模式。
6.命令模式:用一種鬆耦合的方式來設計程序,使得請求發送者和請求接收者可以消除彼此之間的耦合關係
命令(command)指的是一個執行某些特定事情的指令
應用場景:使用對象字面量得形式定義一個命令。
7.組合模式: 用小得子對象來構建更大得對象,而這些小得子對象自己也許時由更小得」孫對象「構建成得。
應用場景:掃描文件夾種得文件
8.模板方法模式:模板方法模式由兩部分結構組成,第一部分時抽象父類,第二部分是具體得實現子類。
應用場景:繼承,子類直接調用父類得模板函數來執行。
9.享元模式:享元(flyweight)模式是一種用於性能優化的模式,它的目標是儘可能減小共享對象的數量
強調將對象的屬性劃分爲內部狀態(屬性)與外部狀態(屬性)。內部狀態用於對象的共享,一般不變;而外部狀態則剝離開來,由具體的場景決定
應用場景:一個班級男女測量身高,性別爲內部狀態,其餘屬性爲外部狀態。
10.職責鏈模式:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係,將這些對象連成一條鏈,並沿着這條鏈 傳遞該請求,直到有一個對象處理它爲止
應用場景:以展現不一樣類型的變量爲例,設置一條職責鏈,能夠免去多重if條件分支
11.中介者模式:全部的相關 對象都經過中介者對象來通訊,而不是互相引用,因此當一個對象發生改變時,只須要通知中介者對象便可
12.裝飾者模式:
13.狀態模式:
14.適配器模式:
15.外觀模式:
http://www.javashuo.com/article/p-ghjzqliu-k.html
(11)事件流的三個階段:
事件的處理過程主要有三個階段:捕獲階段,目標階段,冒泡階段;
1.捕獲階段:當咱們在 DOM 樹的某個節點發生了一些操做(例如單擊、鼠標移動上去),就會有一個事件發射過去。這個事件從 Window 發出,不斷通過下級節點直到觸發的目標節點。在到達目標節點以前的過程,就是捕獲階段(Capture Phase)。事件由頁面元素接收,逐級向下,到具體的元素。
2.目標階段:當事件不斷的傳遞直到目標節點的時候,最終在目標節點上觸發這個事件,就是目標階段。具體的元素自己
3.冒泡階段:事件冒泡即事件開始時,由最具體的元素接收(也就是事件發生所在的節點),而後逐級傳播到較爲不具體的節點。跟捕獲相反,具體元素自己,逐級向上,到頁面元素(咱們平時用的事件綁定就是利用的事件冒泡的原理)。
事件捕獲:當使用事件捕獲時,父級元素先觸發,子元素後觸發。
事件冒泡:當使用事件冒泡時,子級元素先觸發,父元素後觸發。
W3C : 任何事件發生時,先從頂層開始進行事件捕獲,直到事件觸發到達事件源,再從事件源向上進行事件捕獲(事件冒泡)。
事件傳播的阻止方法:
在W3C中,使用stopPropagation()方法。
在IE下使用cancelBubble = true方法。
阻止默認行爲:
在W3c中,使用preventDefault()方法。
(12)判斷是不是數組的幾種實現方式:
1.Array.isArray(): 返回true
let arr = []; console.log(arr instanceof Array); //true
4.寫一個函數方法
let arr = []; var isType = function (obj) { return Object.prototype.toString.call(obj).slice(8,-1); } console.log(isType(arr) == 'Array'); //true
(13)MVC和MVVC模式的區別:
MVC:M仍是表示Modal層,負責與後臺交互數據,V表示View,負責頁面上DOM的渲染,C表示綁定在DOM元素上的事件,當Controllor中的事件被調用,會去調用Modal中的數據,而後交給View從新渲染數據
MVVC:react、vue這倆個框架的核心理念都是數據驅動頁面渲染,同時他們都是MVVM模式的框架,MVVM模式中的M仍是固定表示Modal,V仍是表死View,這倆個基本都是不會發生變化,一個頁面必然須要數據和渲染倆個部分,那麼變化的是如何將Modal渲染到View的過程變了,在MVVM模式中,將View和Modal綁定在一塊兒,只要Modal發生了變化,View就會自動更新,不須要咱們認爲的再去寫如何操做DOM更新的過程了
(14)數據類型是放入堆?仍是棧?
js中數據對於存儲能夠分爲兩種數據類型:基本類型和引用類型
基本類型:Number,String,Boolean,Null,Undefined
這些類型的值存放在棧區,函數調用時傳遞的是變量的值(值)。
引用類型:Object,Array,Function
這些類型的對象存放在堆區,對象的地址存放在棧區,函數調用時傳遞的是對象的地址(址)。
(15)函數的科裏化?
科裏化:是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。
或者:const curry = ( fn, arr = []) => { return (...args) => { return ( a => { //a是一個數組 if(a.length === fn.length) { return fn(...a) }else{ return curry(fn, a) } })([...arr, ...args]) //這裏把arr和args攤開成一個數組賦值給a } }const curry = ( fn, arr = []) => (...args) => ( a => a.length === fn.length? fn(...a) : curry(fn, a))([...arr, ...args])
let curryPlus = curry((a,b,c,d)=>a+b+c+d) curryPlus(1,2,3)(4) //返回10 curryPlus(1,2)(4)(3) //返回10 curryPlus(1,2)(3,4) //返回10
(16)用原生的方式實現數組去重?
function merge(arr) {
if (!Array.isArray(arr) || arr.length == 0)
return [];
var ret = [] ;
for (var i = 0; i < arr.length; i++) {
// 或者 ret.indexOf(arr[i] == -1)
if (arr.indexOf(arr[i]) == i)
{ret.push(arr[i]);}
}
return ret;
}
(17)防抖和節流?
防抖:觸發高頻事件後N秒內只會執行一次,若是n秒內高頻事件再次被觸發,則從新計算時間。
舉例:在百度搜索時,每次輸入以後都會有聯想詞彈出,這個控制聯想詞的方法就是不多是輸入框內容一改變就觸發的,他必定是當你結束輸入一段時間以後才觸發的。
function debounce(fn,delay){
//記錄上一次的延時器
var timer = null;
return function(){
//清除上一次延時器
clearTimeout(timer);
//從新設置新的延時器
timer = setTimeout(function(){
fn.apply(this);
},delay);
}
}
節流:高頻事件觸發,但在N秒內只會執行一次,因此節流會稀釋函數執行的頻率
舉例:預約一個函數只有在大於等於執行週期時才執行,週期內調用不執行,就像淘寶中搶購某一件熱賣商品時,你不斷的點擊刷新或者購買,但是總有一段時間點擊沒有效果,這裏就是節流。
代碼舉例:
function scall(fn,delay){
// 記錄上一次函數觸發的時間
var lastTime = 0;
return function (){
// var nowTime = Date.now();
if(nowTime - lastTime>delay){
fn();
lastTime = nowTime;
}
}
}
document.onscroll = scall(function(){ console.log('scroll事件被觸發了'+Date.now());},200)
(18)js異步編程的方法?
1.事件的回調函數
2.定時器
3.promise
4.async ...await
5.generator 函數
2.關於es6
http://www.javashuo.com/article/p-gxswledk-nk.html
(1)箭頭函數
1.經過=>函數能夠更簡潔快速的定義一個函數
2.若是箭頭函數不須要傳參或須要多個傳參,就須要使用()括起來。
3.若是箭頭函數的代碼塊部分多於一條語句,就要使用大括號將他們括起來,並使用return語句返回。
4.若是箭頭函數只有一行語句,且不須要返回值,不用寫大括號了
(2)Promise的用法以及實現原理
(3)說出es6新特性
(4)set數據結構
Set
自己是一個構造函數,用來生成 Set 數據結構,可用於數組去重
實例:
.add() 添加成員,返回Set結構自己
.size 返回Set實例的成員總數
.delete() 刪除某值,返回Set結構自己
.has() 返回一個布爾值,表示該值是否爲Set的成員
.clear() 清除全部成員,沒有返回值
.keys() 返回鍵名的遍歷器
.values() 返回鍵值的遍歷器
.entries() 返回鍵值對的遍歷器
.forEach() 使用回調函數遍歷每一個成員,沒有返回值
(5)map數據結構
在JavaScript中對象(Object)本質是鍵值對的集合,但只能用字符串看成鍵。而Map 數據結構的出現就是爲了解決這個限制,它相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵
.set(key, value) 設置key對應的value,返回 Map 結構。若是key已經有值,則鍵值會被更新。
.get(key) 讀取key對應的鍵值,若是找不到key,返回undefined。
.has(key) 方法返回一個布爾值,表示某個鍵是否在當前 Map 對象之中。
.delete() 方法刪除某個鍵,返回true,若是刪除失敗,返回false。
.clear() 方法清除全部成員,沒有返回值。
.keys(): 返回鍵名的遍歷器。
.values():返回鍵值的遍歷器。
.entries():返回全部成員的遍歷器。
.forEach():遍歷 Map 的全部成員。
(6)let和const命令
es5只有兩種聲明變量的方法:var命令和function命令。es6除了let和const命令,另外兩種聲明變量的方法: import命令和class命令。因此 es6一共有6種方法。
let和const相同的地方:1.只在聲明所在的塊級做用域內有效 。
2.不可重複聲明。
3.一樣存在暫時性死區,只能在聲明的位置後面使用。
(7)變量的解構賦值
1.數組解構賦值:
2.對象解構賦值:
3.字符串解構賦值:
4.默認值,無論是對象仍是數組,解構賦值都容許指定默認值:
用途:1.交換變量的值
例子1:
2.從函數返回多個值
// 數組
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 對象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
3.函數參數的定義
4.提取json數據
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
6.輸入模塊的指定方法
3.關於css2和css3
(1)BFC:塊級格式化上下文"
佈局規則:
1.內部的BOX會在垂直方向,一個接一個的放置。
2.box垂直方向的距離由margin決定,屬於同一個BFC的兩個相鄰box的margin會發生重疊。
3.每一個盒子(塊盒與行盒)的margin box的左邊,與包含塊border box 的左邊相接觸(對於從左往右的格式化,不然相反)。即便存在浮動也是如此。
4.BFC的區域不會與float box重疊。
5.BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。
6.計算bfc的高度時,浮動元素也參與計算。
建立BFC:一、float 的值不是none
二、position的值不是static 或者relative
三、display的值是inline-block、table-cell、flex、table-caption 或者inline-flex
四、overflow的值不是visible
1.BFC的做用:1.利用BFC避免margin重疊
2.自適應兩欄佈局 left<div> : float :left, right<div>: overflow:hidden
3.清除浮動:當咱們不給父節點設置高度,子節點設置浮動的時候,會發生高度塌 陷,這個時候咱們就要清楚浮動
總結:BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此
由於BFC內部的元素和外部的元素絕對不會互相影響,所以, 當BFC外部存在浮動時,它不該該影響BFC內部Box的佈局,BFC會經過變窄,而不與浮動有重疊。一樣的,當BFC內部有浮動時,爲了避免影響外部元素的佈局,BFC計算高度時會包括浮動的高度。避免margin重疊也是這樣的一個道理
(2)清除浮動3種方式:
(3)實現垂直水平居中(新老方式)
一、老方式
#wrap{
width:500px;
height:500px;
background:grey;
position:relative;
}
#wrap .box{
width:200px;
height:200px;
background:pick;
//方式1:
position:absolute;
top:50%;
left:50%;
margin-left:-100px;
margin-top:-100px;
//方式2:
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
margin:auto;
//方式3
transform:translate(-50%,-50%);
}
二、新方式
#wrap{
display:flex;
justify-content:center;
align-items:center;
}
4.關於react
redux中間件原裏:改裝dispath
(1)hoc:
定義:一種React的進階使用方法,主要仍是爲了便於組件的複用。HOC就是一個方法,獲取一個組件,返回一個更高級的組件
何時使用hoc?
組件添加或者修改一些特定的props,一些權限的管理,或者一些其餘的優化之類的。而若是這個功能是針對多個組件的,同時每個組件都寫一套相同的代碼,明顯顯得不是很明智,因此就能夠考慮使用HOC。
例子:react-redux的connect方法就是一個HOC,他獲取wrappedComponent,在connect中給wrappedComponent添加須要的props。
hoc能夠作什麼?
1.代碼複用,代碼模塊化
2.增刪改props
3.渲染劫持 :組件要在data沒有加載完的時候,顯示loading。。。
Hoc有什麼用例?
1.react redux的connect方法,經過這個hoc方法,監聽redux store ,而後把下級組件須要的state(經過mapStateToPtops獲取)和action creator(經過mapDispatchToProps 獲取)綁定到wrappedComponent的props上
2.logger和debugger 能夠用來監控父級組件傳入的props的改變:
3.頁面權限管理:能夠經過hoc對組件進行包裹,當跳轉到當前頁面的時候,檢查用戶是否含有對應的權限,若是有的話,渲染頁面,若是沒有的話,跳轉到其餘頁面(好比無權限頁面,或者登錄頁面)。
使用Hoc須要注意什麼?
1.儘可能不要隨意修改下級組件須要的props
修改父級傳遞給下級的props是有必定風險的,可能會形成下級組件發生錯誤。
2.ref沒法獲取你想要的ref
由於這裏的component通過hoc的封裝,已是hoc裏面的那個component了,因此你沒法獲取你想要的那個ref(wrappedComponent的ref)。
解決方法:
a> 像react redux的connect方法同樣,在裏面添加一個參數,好比withRef,組件中檢查到這個flag了,就給下級組件添加一個ref ,並經過getWrappedinstance方法獲取。
b> 父級經過傳遞一個方法,來獲取ref
先看父級組件:
component上面綁定的Static方法會丟失
好比:原來在Component上面綁定了一些static方法,MyComponent.staticMethod = o=>o.可是因爲通過Hoc的包裹,父級組件拿到的已經不是原來的組件了,因此固然沒法獲取staicMethod方法了
https://segmentfault.com/a/1190000008112017?_ea=1553893
(2)hook:
(3)虛擬dom的缺點:
(4)dva和redux相比較優缺點:
dva是一個基於redux和redux-saga的數據流方案,dva還額外內置了react-router和fetch,因此也能夠理解爲一個輕量級的應用框架。
1.dva封裝了redux,減小不少重複代碼好比action reducers常量
2.dva操做都是在models層,經過namespace做爲key,標識不一樣的模塊state。state存儲數據。
3.reducers跟傳統的react-redux寫法一致,全部的操做放在reducers對象內。
4.異步操做寫在effects對象內:
其實*fetchList 就是function *fetchList ,是個Generator狀態機
call,put實際上是saga的寫法,dva集成了saga。
5.ui組件調用使用@connect包裹就能夠從this.props上調用方法和數據。
6.dva-loading能夠自動處理loading狀態,不用一遍遍的寫showLoading和hideLoading。
優勢
(5)從3方面說說diff算法:
1.tree Diff
(1)react經過updateDepth對於Virtual DOM樹進行層級控制。
(2)對樹分層比較,兩棵樹只對同一層次節點進行比較,若是該節點不存在時,則該節點及其子節點會被徹底刪除,不會再進一步比較。
(3)只需遍歷一次,就 能完成整棵樹DOM樹的比較。
(4) diff只簡單考慮同層級的節點位置互換,若是時垮層級的話,只有建立節點和刪除節點的操做。
2.Component Diff
react對不一樣組件間的比較,有三種策略」
(1)同一個類型的兩個組件,就按原策略(層級比較)繼續比較Virtual DOM樹便可。
(2)同一類型的兩個組件,組件A變化爲組件B時,可能Virtual Dom沒有任何變化,若是知道這點(變換的過程當中,Virtual Dom沒有改變),可節省大量計算時間,因此用戶能夠經過shouldComponentUpdate()來判斷是否須要diff計算
(3)不一樣類型的組件,將一個(將被改變的)組件判斷爲dirty component (髒組件),從而替換整個組件的全部節點。
若是組件D和組件G的結構類似,可是react判斷時不一樣類型的組件,則不會比較其結構,而是刪除組件D及其子節點,建立組件G及其子節點。
3.Element Diff
當節點處於同一層級時,diff提供三種節點操做:刪除、插入、移動。
https://www.jianshu.com/p/3ba0822018cf
(6)react框架的原理:
react的設計原理就是其引入的虛擬dom機制:
一、react用javascript在瀏覽器端實現了一套虛擬dom api。
二、基於react開發的時候全部的dom構造都是基於虛擬dom進行的
三、每當有state更改的時候,react就從新render一整套虛擬dom樹,
react機制會將當前的整個dom樹和上一次的dom樹進行對比
取到diff,進行真實的dom更改。
四、其實state也有一部分實現的是數據、html片斷綁定,
直接更新的數據是包含的
深層次一點就是react的diff算法是怎麼理解的。
錯誤的看法:我曾經覺得diff算法,就是深層次的diff,算法運算時只比較
不一樣的。但其實當時淺顯的想法,確實是diff運算的結果,但不是
diff運算的算法。
一、tree diff
React對Virtual DOM樹進行層級控制,只會對相同層級的DOM節點進行比
較,即同一個父元素下的全部子節點,當發現節點已經不存在了,則會刪除掉
該節點下全部的子節點,不會再進行比較。這樣只須要對DOM樹進行一次遍
歷,就能夠完成整個樹的比較。
即便說a節點以及他的子節點被移動,可是react只關注同級比較,在第二層
把a及其子節點刪了,在第三層再從新建立,因此diff運算量大,影響性能
不建議setState直接更改樹的結構。最好是state顆粒度小,只改變樹中
的某一個小的節點,那麼diff的時候只會深度比較這一個小節點。
二、componnet diff
假如說由於某個條件切換,因此要顯示不一樣的組件。
一、比較兩個組件的類型(D和G)
二、若是(D和G)不是同一類型,進行diff算法,分析會影響性能
直接刪掉上一個虛擬dom組件。 從新建立新的組件。
若是是同一類型的組件,會按照層級策略深層對比每一個節點。
三、element diff
精確的對屬於同一層級的節點diff時,提供了3種節點操做,分別爲INSERT_MARKUP(插入),MOVE_EXISTING(移動),REMOVE_NODE(刪除)。
若是同一層級,沒有這個新節點會新增插入
若是同一層級,若是有新節點,可是屬性不同,會複用節點,賦值屬性
若是同一層次,舊dom有,新dom沒有,會刪除這個節點。
原文連接:https://blog.csdn.net/running_shuai/java/article/details/80284698
總結:setState()觸發一次組件重繪,其實就是虛擬dom從新生成,除非在
shouldComponentUpdate()中實現了一些條件渲染邏輯。來容許和阻止是否須要
調用指定組件的 render 方法。其實這個深刻邏輯就是他觸發了render,只是是
否觸發了內部的diff算法,return false 的時候,不diff,render出來的新
舊dom同樣。diff算法的複雜度爲0。
(7)redux:
1>redux 是一個獨立專門用於作狀態管理的js庫,不是react插件庫
2>做用:集中式管理react應用中多個組件共享的狀態和從後臺獲取的數據。
react-redux簡化redux的編碼
redux-thunk實現redux的異步編程
使用redux devTools實現chrome 中redux的調試
(8)爲何虛擬dom會提升性能?
(9)this.setStatus 是異步仍是同步?
setState
只在合成事件和鉤子函數中是「異步」的,在原生事件和 setTimeout
中都是同步的。setState
的「異步」並非說內部由異步代碼實現,其實自己執行的過程和代碼都是同步的,只是合成事件和鉤子函數的調用順序在更新以前,致使在合成事件和鉤子函數中無法立馬拿到更新後的值,形式了所謂的「異步」,固然能夠經過第二個參數 setState(partialState, callback) 中的callback拿到更新後的結果。setState
的批量更新優化也是創建在「異步」(合成事件、鉤子函數)之上的,在原生事件和setTimeout 中不會批量更新,在「異步」中若是對同一個值進行屢次 setState
, setState
的批量更新策略會對其進行覆蓋,取最後一次的執行,若是是同時 setState
多個不一樣的值,在更新時會對其進行合併批量更新。
(10)生命週期?
5.前端優化
6.前端工程化
1.服務端模塊化
1、commonJS 對模塊的定義很是簡單,主要分爲模塊引用,模塊定義和模塊標識3個部分。
1)模塊的引用
var add = require('./add.js);
2) 模塊定義
module.exports.add = function(){
...
}
3)能夠在一個文件中引入模塊並導出另外一個模塊
var add = require('./add .js');
module.exports.increment = function(){
return add (val,1);
}
其實 ,一個文件表明一個模塊,一個模塊除了本身的函數做用域以外,最外層還有一個模塊做用域,module就是表明這個模塊,
exports是module的屬性,require也是這個模塊的上下文中,用來引入外部模塊。
3)模塊標識
模塊標識就是require()函數的參數,規範是這樣的
1.必須是字符串
2.能夠是以./ ../開頭的相對路徑
3.能夠是絕對路徑
4.能夠省略後綴名
2、node.js 模塊化實現
1.node中一個文件 就是一個模塊-----module
一個模塊就是一個Module的實例
2.node模塊分類:核心模塊和文件模塊
核心模塊:就是node內置的模塊好比http,path等。在node的源碼的編譯時,核心模塊就一塊兒被編譯進了二進制執行文件,部分核心模塊(內建模塊)被直接加載進內存中。
文件模塊:就是外部引入的模塊如node—modules裏面經過npm按裝模塊,或者咱們項目工程裏本身寫一個js文件或者json文件。
node模塊的引入過程,通常要通過三個步驟
路徑分析
文件定位
編譯執行
核心模塊:會省略 文件定位和編譯執行,而且在路徑分析中會優先判斷,加載速度比通常模塊更快。標識:require(‘http’);
文件模塊:三個步驟都要經歷。require('./c.js');以. / 或者.. /絕對路徑開頭。
3、AMD:異步模塊加載規範與CommonJS的主要區別就是異步模塊加載,就是模塊加載過程當中即便require的模塊尚未獲取到,也不會影響後面代碼的執行。
4、CMD:通用模塊規範,與AMD規範的主要區別在於定義模塊和依賴引入的部分,AMD須要在聲明模塊的時候指定全部的依賴,經過形參傳遞依賴到模塊內容中。在依賴示例部分,CMD支持動態引入,require、exports、module經過形參傳遞給模塊,在須要依賴模塊時,隨時調用require()引入便可。
5、UMD 通用模塊規範
6、es6模塊
1)導出一個變量
export var name=‘pengpeng’;
2)導出一個函數
export function foo(x,y){}
3)經常使用導出方式(推薦)
const name = ‘dingman’;
const age = ‘18’;
export{name,age};
4)As用法
const s =1;
export {
s as t,
s as m,
}
能夠利用as將模塊輸出屢次。
Es6模塊使用-----import
1) 通常用法
import {name,age} from ‘./person,js';
2) As 用法
import {name as personName} from './person.js';
import命令具備提高效果,會提高到整個模塊的頭部,首先執行,以下也不會報錯:
getName();
import {getName} from ’person_module';
3)總體模塊加載*
export name = 'xixi';
export age = 23;
// 逐一加載
import {age,name} from './person.js';
// 總體加載
import * as person from './person.js';
console.log(person.name);
console.log(person.age);
es6模塊使用 ------export default
使用export default 命令,須要注意的是使用export default命令時,import 是不須要加{}的,而不使用export default時,import是必須加{}。
示例以下:
//person.js export function getName() { ... } //my_module import {getName} from './person.js'; -----------------對比--------------------- //person.js export default function getName(){ ... } //my_module import getName from './person.js';
export default 實際上是導出一個叫作default的變量,因此其後面不能跟變量聲明語句。
//錯誤
export default var a = 1;
值得注意的是 咱們能夠同時使用export和export default
commonjs是運行時加載,es6是編譯時加載,又有什麼區別呢?
//person.js export name = 'dingman'; export default function getName(){ ... } //my_module import getName, { name } from './person.js';
ES6模塊的設計思想,是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。因此說ES6是編譯時加載,不一樣於CommonJS的運行時加載(實際加載的是一整個對象),ES6模塊不是對象,而是經過export命令顯式指定輸出的代碼,輸入時也採用靜態命令的形式
//ES6模塊 import { basename, dirname, parse } from 'path'; //CommonJS模塊 let { basename, dirname, parse } = require('path');
七:webpack模塊化
https://zhuanlan.zhihu.com/p/41568986
https://zhuanlan.zhihu.com/p/42853909
7.websocket
(1)websocket和http區別?
http協議是用在應用層的協議,他是基於tcp協議的,http協議創建連接也必需要有三次握手才能發送信息。
http連接分爲短連接,長連接,短連接是每次請求都要三次握手才能發送本身的信息。即每個request對應一個response。長連接是在必定的期限內保持連接。保持TCP鏈接不斷開。客戶端與服務器通訊,必需要有客戶端發起而後服務器返回結果。客戶端是主動的,服務器是被動的。
WebSocket
WebSocket他是爲了解決客戶端發起多個http請求到服務器資源瀏覽器必需要通過長時間的輪訓問題而生的,他實現了多路複用,他是全雙工通訊。在webSocket協議下客服端和瀏覽器能夠同時發送信息。
創建了WebSocket以後服務器沒必要在瀏覽器發送request請求以後才能發送信息到瀏覽器。這時的服務器已有主動權想何時發就能夠發送信息到服務器。並且信息當中沒必要在帶有head的部分信息了與http的長連接通訊來講,這種方式,不只能下降服務器的壓力。並且信息當中也減小了部分多餘的信息。
(2)webSocket如何實現斷線重連?
var ws_heart_i = null;
/**
* websocket 每1分鐘發一次心跳
*/
function ws_heart() {
if (ws_heart_i) clearInterval(ws_heart_i);
ws_heart_i = setInterval(function () {
console.log('ws_heart');
var func = function () {
var data = {type: 'ping'};
ws.send(JSON.stringify(data));
};
ws_execute(func);
}, 60000);
}
原文連接:https://blog.csdn.net/sybil06/java/article/details/88821125
8.瀏覽器存儲
9.網絡問題
(1)http 請求的所有過程?
1.DNS解析:將域名地址解析爲ip地址
-瀏覽器DNS緩存
-系統DNS緩存
-路由DNS緩存
-網絡運營商DNS緩存
-遞歸搜索:blog.baidu.com
-.com域名下查找DNS解析
-.baidu域名下查找DNS解析
-blog域名下查找DNS解析
-出錯了
2.TCP鏈接,TCP三次握手
-第一次握手,由瀏覽器發起,告訴服務器我要發送請求了
-第二次握手,由服務器發起,告訴瀏覽器我準備接受了,你趕忙發送吧
-第三次握手,由瀏覽器發送,告訴服務器, 我立刻就發了,準備接受吧
3.發送請求
-請求報文,http協議的通訊內容
4.接受響應
-響應報文
5.渲染頁面
-碰見HTML標記,瀏覽器調用HTML解析器解析成Token並構建成dom樹
-碰見style/link標記,瀏覽器調用css解析器,處理css標記並構建cssom樹
-碰見script標記,調用JavaScript解析器,處理script代碼(綁定事件,修改dom樹/cssom樹)
-將dom樹和cssom樹合併成一個渲染樹
-根據渲染樹來計算佈局,計算每一個節點的幾何信息(佈局)
-將各個節點顏色繪製到屏幕上(渲染)
注意:
這個5個步驟不必定按照順序執行,若是dom樹或cssom樹被修改了,可能會執行屢次佈局和渲染,
每每實際頁面中,這些步驟會執行屢次的
6.斷開鏈接,TCP四次揮手
第一次揮手,由瀏覽器發起的,發送給服務器,我東西發送完了(請求報文),你準備關閉吧。
第二次揮手,由服務器發起的,告訴瀏覽器,我東西接收完了(請求報文),我準備關閉了,你也準備吧
第三次揮手,由服務器發起,告訴瀏覽器,我東西發送完了(響應報文),你準備關閉吧。
第四次揮手,由瀏覽器發起,告訴服務器,我東西接受完了,我準備關閉了(響應報文),你也準備吧。
(2)如何處理跨域問題?
(3)http緩存機制?
(4)http狀態碼
狀態碼
狀態代碼爲3位數字。
1xx:指示信息--表示請求已接收,繼續處理。
2xx:成功--表示請求已被成功接收、理解、接受。
3xx:重定向--要完成請求必須進行更進一步的操做。
4xx:客戶端錯誤--請求有語法錯誤或請求沒法實現。
5xx:服務器端錯誤--服務器未能實現合法的請求。
10 .移動端如何實現適配
11.react選型?
12.react和vue相比較
相同點:
1.都有組件化開發和virtual DOM
2.都支持props進行父子組件間數據通訊
3.都支持數據驅動視圖,不直接操做真實DOM,更新狀態數據界面就自動更新
4.都支持服務端渲染
5.都有支持native的方案,react的react native ,vue的weex
不一樣點:
1.數據綁定:vue實現了數據的雙向綁定,react數據流動時單向的。
2.組件寫法不同,react推薦的作法是JSX,也就是把html和css所有都寫進javascript了,即「all in js」 vue推薦的作法是webpack+vue-loader的單文件組件格式,即html,css,js 寫在同一個文件。
3.state對象在react應用中不可變的,須要使用setState方法更新狀態;在vue中,state對象不是必須的,數據由data屬性在vue對象中管理
4.virtual Dom不同,vue會跟蹤每個組件的依賴關係,不須要從新渲染整個組件樹,而對於react而言,每當應用的狀態被改變時,所有組件都會從新渲染,因此react中會須要shouldComponentUpdate 這個生命週期函數方法來進行控制
5.react嚴格上只針對MVC的view層,vue則是mvvm模式。
12.飛冰和antdesign?