1.1. 隊列的數(shù)據(jù)結(jié)構(gòu)
創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、網(wǎng)站設(shè)計、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的莫力達(dá)網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
隊列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。
1.2. Java實現(xiàn)
QueueTest
package ch04;
public class QueueTest {
public static void main(String[] args) {
ArrayQueue queue = new ArrayQueue(10);
System.out.println(queue.isEmpty());
for (int i = 0; i 10; i++) {
queue.insert(i);
}
System.out.println(queue.isFull());
while (!queue.isEmpty()) {
System.out.println(queue.remove());
}
}
}
class ArrayQueue {
private int[] arrInt;// 內(nèi)置數(shù)組
private int front;// 頭指針
private int rear;// 尾指針
public ArrayQueue(int size) {
this.arrInt = new int[size];
front = 0;
rear = -1;
}
/**
* 判斷隊列是否為空
*
* @return
*/
public boolean isEmpty() {
return front == arrInt.length;
}
/**
* 判斷隊列是否已滿
*
* @return
*/
public boolean isFull() {
return arrInt.length - 1 == rear;
}
/**
* 向隊列的隊尾插入一個元素
*/
public void insert(int item) {
if (isFull()) {
throw new RuntimeException("隊列已滿");
}
arrInt[++rear] = item;
}
/**
* 獲得對頭元素
*
* @return
*/
public int peekFront() {
return arrInt[front];
}
/**
* 獲得隊尾元素
*
* @return
*/
public int peekRear() {
return arrInt[rear];
}
/**
* 從隊列的對頭移除一個元素
*
* @return
*/
public int remove() {
if (isEmpty()) {
throw new RuntimeException("隊列為空");
}
return arrInt[front++];
}
}
運行結(jié)果如下:
false
true
1
2
3
4
5
6
7
8
9
HTML、CSS相關(guān)
html5新特性、語義化
瀏覽器渲染機制、重繪、重排
網(wǎng)頁生成過程:
重排(也稱回流): 當(dāng) DOM 的變化影響了元素的幾何信息( DOM 對象的位置和尺寸大小),瀏覽器需要重新計算元素的幾何屬性,將其安放在界面中的正確位置,這個過程叫做重排。 觸發(fā):
重繪: 當(dāng)一個元素的外觀發(fā)生改變,但沒有改變布局,重新把元素外觀繪制出來的過程,叫做重繪。 觸發(fā):
重排優(yōu)化建議:
transform 不重繪,不回流 是因為 transform 屬于合成屬性,對合成屬性進行 transition/animate 動畫時,將會創(chuàng)建一個合成層。這使得動畫元素在一個獨立的層中進行渲染。當(dāng)元素的內(nèi)容沒有發(fā)生改變,就沒有必要進行重繪。瀏覽器會通過重新復(fù)合來創(chuàng)建動畫幀。
css盒子模型
所有 HTML 元素可以看作盒子,在CSS中, "box model" 這一術(shù)語是用來設(shè)計和布局時使用。 CSS 盒模型本質(zhì)上是一個盒子,封裝周圍的 HTML 元素,它包括:邊距,邊框,填充,和實際內(nèi)容。 盒模型允許我們在其它元素和周圍元素邊框之間的空間放置元素。
css樣式優(yōu)先級
!importantstyleidclass
什么是BFC?BFC的布局規(guī)則是什么?如何創(chuàng)建BFC?BFC應(yīng)用?
BFC 是 Block Formatting Context 的縮寫,即塊格式化上下文。 BFC 是CSS布局的一個概念,是一個環(huán)境,里面的元素不會影響外面的元素。 布局規(guī)則:Box是CSS布局的對象和基本單位,頁面是由若干個Box組成的。元素的類型和display屬性,決定了這個Box的類型。不同類型的Box會參與不同的 Formatting Context 。 創(chuàng)建:浮動元素 display:inline-block position:absolute 應(yīng)用: 1.分屬于不同的 BFC 時,可以防止 margin 重疊 2.清除內(nèi)部浮動 3.自適應(yīng)多欄布局
DOM、BOM對象
BOM(Browser Object Model) 是指瀏覽器對象模型,可以對瀏覽器窗口進行訪問和操作。使用 BOM,開發(fā)者可以移動窗口、改變狀態(tài)欄中的文本以及執(zhí)行其他與頁面內(nèi)容不直接相關(guān)的動作。 使 JavaScript 有能力與瀏覽器"對話"。 DOM (Document Object Model) 是指文檔對象模型,通過它,可以訪問 HTML 文檔的所有元素。 DOM 是 W3C (萬維網(wǎng)聯(lián)盟)的標(biāo)準(zhǔn)。 DOM 定義了訪問 HTML 和 XML 文檔的標(biāo)準(zhǔn): "W3C 文檔對象模型(DOM)是中立于平臺和語言的接口,它允許程序和腳本動態(tài)地訪問和更新文檔的內(nèi)容、結(jié)構(gòu)和樣式。" W3C DOM 標(biāo)準(zhǔn)被分為 3 個不同的部分:
什么是 XML DOM ? XML DOM 定義了所有 XML 元素的對象和屬性,以及訪問它們的方法。 什么是 HTML DOM? HTML DOM 定義了所有 HTML 元素的對象和屬性,以及訪問它們的方法。
JS相關(guān)
js數(shù)據(jù)類型、typeof、instanceof、類型轉(zhuǎn)換
閉包(高頻)
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù) ——《JavaScript高級程序設(shè)計》
當(dāng)函數(shù)可以記住并訪問所在的詞法作用域時,就產(chǎn)生了閉包,
即使函數(shù)是在當(dāng)前詞法作用域之外執(zhí)行 ——《你不知道的JavaScript》
原型、原型鏈(高頻)
原型: 對象中固有的 __proto__ 屬性,該屬性指向?qū)ο蟮? prototype 原型屬性。
原型鏈: 當(dāng)我們訪問一個對象的屬性時,如果這個對象內(nèi)部不存在這個屬性,那么它就會去它的原型對象里找這個屬性,這個原型對象又會有自己的原型,于是就這樣一直找下去,也就是原型鏈的概念。原型鏈的盡頭一般來說都是 Object.prototype 所以這就是我們新建的對象為什么能夠使用 toString() 等方法的原因。
特點: JavaScript 對象是通過引用來傳遞的,我們創(chuàng)建的每個新對象實體中并沒有一份屬于自己的原型副本。當(dāng)我們修改原型時,與之相關(guān)的對象也會繼承這一改變。
this指向、new關(guān)鍵字
this 對象是是執(zhí)行上下文中的一個屬性,它指向最后一次調(diào)用這個方法的對象,在全局函數(shù)中, this 等于 window ,而當(dāng)函數(shù)被作為某個對象調(diào)用時,this等于那個對象。 在實際開發(fā)中, this 的指向可以通過四種調(diào)用模式來判斷。
new
作用域、作用域鏈、變量提升
繼承(含es6)、多種繼承方式
(1)第一種是以 原型鏈的方式來實現(xiàn)繼承 ,但是這種實現(xiàn)方式存在的缺點是,在包含有引用類型的數(shù)據(jù)時,會被所有的實例對象所共享,容易造成修改的混亂。還有就是在創(chuàng)建子類型的時候不能向超類型傳遞參數(shù)。
(2)第二種方式是使用 借用構(gòu)造函數(shù) 的方式,這種方式是通過在子類型的函數(shù)中調(diào)用超類型的構(gòu)造函數(shù)來實現(xiàn)的,這一種方法解決了不能向超類型傳遞參數(shù)的缺點,但是它存在的一個問題就是無法實現(xiàn)函數(shù)方法的復(fù)用,并且超類型原型定義的方法子類型也沒有辦法訪問到。
(3)第三種方式是 組合繼承 ,組合繼承是將原型鏈和借用構(gòu)造函數(shù)組合起來使用的一種方式。通過借用構(gòu)造函數(shù)的方式來實現(xiàn)類型的屬性的繼承,通過將子類型的原型設(shè)置為超類型的實例來實現(xiàn)方法的繼承。這種方式解決了上面的兩種模式單獨使用時的問題,但是由于我們是以超類型的實例來作為子類型的原型,所以調(diào)用了兩次超類的構(gòu)造函數(shù),造成了子類型的原型中多了很多不必要的屬性。
(4)第四種方式是 原型式繼承 ,原型式繼承的主要思路就是基于已有的對象來創(chuàng)建新的對象,實現(xiàn)的原理是,向函數(shù)中傳入一個對象,然后返回一個以這個對象為原型的對象。這種繼承的思路主要不是為了實現(xiàn)創(chuàng)造一種新的類型,只是對某個對象實現(xiàn)一種簡單繼承,ES5 中定義的 Object.create() 方法就是原型式繼承的實現(xiàn)。缺點與原型鏈方式相同。
(5)第五種方式是 寄生式繼承 ,寄生式繼承的思路是創(chuàng)建一個用于封裝繼承過程的函數(shù),通過傳入一個對象,然后復(fù)制一個對象的副本,然后對象進行擴展,最后返回這個對象。這個擴展的過程就可以理解是一種繼承。這種繼承的優(yōu)點就是對一個簡單對象實現(xiàn)繼承,如果這個對象不是我們的自定義類型時。缺點是沒有辦法實現(xiàn)函數(shù)的復(fù)用。
(6)第六種方式是 寄生式組合繼承 ,組合繼承的缺點就是使用超類型的實例做為子類型的原型,導(dǎo)致添加了不必要的原型屬性。寄生式組合繼承的方式是使用超類型的原型的副本來作為子類型的原型,這樣就避免了創(chuàng)建不必要的屬性。
EventLoop
JS 是單線程的,為了防止一個函數(shù)執(zhí)行時間過長阻塞后面的代碼,所以會先將同步代碼壓入執(zhí)行棧中,依次執(zhí)行,將異步代碼推入異步隊列,異步隊列又分為宏任務(wù)隊列和微任務(wù)隊列,因為宏任務(wù)隊列的執(zhí)行時間較長,所以微任務(wù)隊列要優(yōu)先于宏任務(wù)隊列。微任務(wù)隊列的代表就是, Promise.then , MutationObserver ,宏任務(wù)的話就是 setImmediate setTimeout setInterval
原生ajax
ajax 是一種異步通信的方法,從服務(wù)端獲取數(shù)據(jù),達(dá)到局部刷新頁面的效果。 過程:
事件冒泡、捕獲(委托)
event.stopPropagation() 或者 ie下的方法 event.cancelBubble = true; //阻止事件冒泡
ES6
Vue
簡述MVVM
MVVM 是 Model-View-ViewModel 縮寫,也就是把 MVC 中的 Controller 演變成 ViewModel。Model 層代表數(shù)據(jù)模型, View 代表UI組件, ViewModel 是 View 和 Model 層的橋梁,數(shù)據(jù)會綁定到 viewModel 層并自動將數(shù)據(jù)渲染到頁面中,視圖變化的時候會通知 viewModel 層更新數(shù)據(jù)。
談?wù)剬ue生命周期的理解?
每個 Vue 實例在創(chuàng)建時都會經(jīng)過一系列的初始化過程, vue 的生命周期鉤子,就是說在達(dá)到某一階段或條件時去觸發(fā)的函數(shù),目的就是為了完成一些動作或者事件
computed與watch
watch 屬性監(jiān)聽 是一個對象,鍵是需要觀察的屬性,值是對應(yīng)回調(diào)函數(shù),主要用來監(jiān)聽某些特定數(shù)據(jù)的變化,從而進行某些具體的業(yè)務(wù)邏輯操作,監(jiān)聽屬性的變化,需要在數(shù)據(jù)變化時執(zhí)行異步或開銷較大的操作時使用
computed 計算屬性 屬性的結(jié)果會被緩存,當(dāng) computed 中的函數(shù)所依賴的屬性沒有發(fā)生改變的時候,那么調(diào)用當(dāng)前函數(shù)的時候結(jié)果會從緩存中讀取。除非依賴的響應(yīng)式屬性變化時才會重新計算,主要當(dāng)做屬性來使用 computed 中的函數(shù)必須用 return 返回最終的結(jié)果 computed 更高效,優(yōu)先使用
使用場景 computed :當(dāng)一個屬性受多個屬性影響的時候使用,例:購物車商品結(jié)算功能 watch :當(dāng)一條數(shù)據(jù)影響多條數(shù)據(jù)的時候使用,例:搜索數(shù)據(jù)
v-for中key的作用
vue組件的通信方式
父子組件通信
父-子 props ,子-父 $on、$emit` 獲取父子組件實例 parent、 parent 、children Ref 獲取實例的方式調(diào)用組件的屬性或者方法 Provide、inject` 官方不推薦使用,但是寫組件庫時很常用
兄弟組件通信
Event Bus 實現(xiàn)跨組件通信 Vue.prototype.$bus = new Vue() Vuex
跨級組件通信
$attrs、$listeners Provide、inject
常用指令
雙向綁定實現(xiàn)原理
當(dāng)一個 Vue 實例創(chuàng)建時,Vue會遍歷data選項的屬性,用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter并且在內(nèi)部追蹤相關(guān)依賴,在屬性被訪問和修改時通知變化。每個組件實例都有相應(yīng)的 watcher 程序?qū)嵗?,它會在組件渲染的過程中把屬性記錄為依賴,之后當(dāng)依賴項的 setter 被調(diào)用時,會通知 watcher重新計算,從而致使它關(guān)聯(lián)的組件得以更新。
v-model的實現(xiàn)以及它的實現(xiàn)原理嗎?
nextTick的實現(xiàn)
vnode的理解,compiler和patch的過程
new Vue后整個的流程
思考:為什么先注入再提供呢??
答:1、首先來自祖輩的數(shù)據(jù)要和當(dāng)前實例的data,等判重,相結(jié)合,所以注入數(shù)據(jù)的initInjections一定要在 InitState 的上面。2. 從上面注入進來的東西在當(dāng)前組件中轉(zhuǎn)了一下又提供給后代了,所以注入數(shù)據(jù)也一定要在上面。
vm.[Math Processing Error]mount(vm.mount(vm.options.el) :掛載實例。
keep-alive的實現(xiàn)
作用:實現(xiàn)組件緩存
鉤子函數(shù):
原理: Vue.js 內(nèi)部將 DOM 節(jié)點抽象成了一個個的 VNode 節(jié)點, keep-alive 組件的緩存也是基于 VNode 節(jié)點的而不是直接存儲 DOM 結(jié)構(gòu)。它將滿足條件 (pruneCache與pruneCache) 的組件在 cache 對象中緩存起來,在需要重新渲染的時候再將 vnode 節(jié)點從 cache 對象中取出并渲染。
配置屬性:
include 字符串或正則表達(dá)式。只有名稱匹配的組件會被緩存
exclude 字符串或正則表達(dá)式。任何名稱匹配的組件都不會被緩存
max 數(shù)字、最多可以緩存多少組件實例
vuex、vue-router實現(xiàn)原理
vuex 是一個專門為vue.js應(yīng)用程序開發(fā)的狀態(tài)管理庫。 核心概念:
你怎么理解Vue中的diff算法?
在js中,渲染真實 DOM 的開銷是非常大的, 比如我們修改了某個數(shù)據(jù),如果直接渲染到真實 DOM , 會引起整個 dom 樹的重繪和重排。那么有沒有可能實現(xiàn)只更新我們修改的那一小塊dom而不要更新整個 dom 呢?此時我們就需要先根據(jù)真實 dom 生成虛擬 dom , 當(dāng)虛擬 dom 某個節(jié)點的數(shù)據(jù)改變后會生成有一個新的 Vnode , 然后新的 Vnode 和舊的 Vnode 作比較,發(fā)現(xiàn)有不一樣的地方就直接修改在真實DOM上,然后使舊的 Vnode 的值為新的 Vnode 。
diff 的過程就是調(diào)用 patch 函數(shù),比較新舊節(jié)點,一邊比較一邊給真實的 DOM 打補丁。在采取 diff 算法比較新舊節(jié)點的時候,比較只會在同層級進行。 在 patch 方法中,首先進行樹級別的比較 new Vnode 不存在就刪除 old Vnode old Vnode 不存在就增加新的 Vnode 都存在就執(zhí)行diff更新 當(dāng)確定需要執(zhí)行diff算法時,比較兩個 Vnode ,包括三種類型操作:屬性更新,文本更新,子節(jié)點更新 新老節(jié)點均有子節(jié)點,則對子節(jié)點進行 diff 操作,調(diào)用 updatechidren 如果老節(jié)點沒有子節(jié)點而新節(jié)點有子節(jié)點,先清空老節(jié)點的文本內(nèi)容,然后為其新增子節(jié)點 如果新節(jié)點沒有子節(jié)點,而老節(jié)點有子節(jié)點的時候,則移除該節(jié)點的所有子節(jié)點 老新老節(jié)點都沒有子節(jié)點的時候,進行文本的替換
updateChildren 將 Vnode 的子節(jié)點Vch和oldVnode的子節(jié)點oldCh提取出來。 oldCh和vCh 各有兩個頭尾的變量 StartIdx和EndIdx ,它們的2個變量相互比較,一共有4種比較方式。如果4種比較都沒匹配,如果設(shè)置了 key ,就會用 key 進行比較,在比較的過程中,變量會往中間靠,一旦 StartIdxEndIdx 表明 oldCh和vCh 至少有一個已經(jīng)遍歷完了,就會結(jié)束比較。
你都做過哪些Vue的性能優(yōu)化?
你知道Vue3有哪些新特性嗎?它們會帶來什么影響?
更小巧、更快速 支持自定義渲染器 支持搖樹優(yōu)化:一種在打包時去除無用代碼的優(yōu)化手段 支持Fragments和跨組件渲染
模板語法99%保持不變 原生支持基于class的組件,并且無需借助任何編譯及各種stage階段的特性 在設(shè)計時也考慮TypeScript的類型推斷特性 重寫虛擬DOM 可以期待更多的編譯時提示來減少運行時的開銷 優(yōu)化插槽生成 可以單獨渲染父組件和子組件 靜態(tài)樹提升 降低渲染成本 基于Proxy的觀察者機制 節(jié)省內(nèi)存開銷
檢測機制 更加全面、精準(zhǔn)、高效,更具可調(diào)試式的響應(yīng)跟蹤
實現(xiàn)雙向綁定 Proxy 與 Object.defineProperty 相比優(yōu)劣如何?
React
1、react中key的作用,有key沒key有什么區(qū)別,比較同一層級節(jié)點什么意思?
2、你對虛擬dom和diff算法的理解,實現(xiàn)render函數(shù)
虛擬DOM 本質(zhì)上是 JavaScript 對象,是對 真實DOM 的抽象表現(xiàn)。 狀態(tài)變更時,記錄新樹和舊樹的差異 最后把差異更新到真正的 dom 中 render函數(shù):
3、React組件之間通信方式?
Context 提供了一個無需為每層組件手動添加 props ,就能在組件樹間進行數(shù)據(jù)傳遞的方法.如果你只是想避免層層傳遞一些屬性,組件組合( component composition )有時候是一個比 context 更好的解決方案。 5. 組件組合缺點:會使高層組件變得復(fù)雜
4、如何解析jsx
5、生命周期都有哪幾種,分別是在什么階段做哪些事情?為什么要廢棄一些生命周期?
componentWillMount、componentWillReceiveProps、componentWillUpdate在16版本被廢棄,在17版本將被刪除,需要使用UNSAVE_前綴使用,目的是向下兼容。
6、關(guān)于react的優(yōu)化方法
使用return null而不是CSS的display:none來控制節(jié)點的顯示隱藏。保證同一時間頁面的DOM節(jié)點盡可能的少。
不要使用數(shù)組下標(biāo)作為key 利用 shouldComponentUpdate 和 PureComponent 避免過多 render function ; render 里面盡量減少新建變量和bind函數(shù),傳遞參數(shù)是盡量減少傳遞參數(shù)的數(shù)量。 盡量將 props 和 state 扁平化,只傳遞 component 需要的 props (傳得太多,或者層次傳得太深,都會加重 shouldComponentUpdate 里面的數(shù)據(jù)比較負(fù)擔(dān)),慎將 component 當(dāng)作 props 傳入
使用 babel-plugin-import 優(yōu)化業(yè)務(wù)組件的引入,實現(xiàn)按需加載 使用 SplitChunksPlugin 拆分公共代碼 使用動態(tài) import ,懶加載 React 組件
7、綁定this的幾種方式
8、對fiber的理解
9、setState是同步還是異步的
10、Redux、React-Redux
Redux的實現(xiàn)流程
用戶頁面行為觸發(fā)一個 Action ,然后 Store 調(diào)用 Reducer ,并且傳入兩個參數(shù):當(dāng)前 State 和收到的 Action 。 Reducer 會返回新的 State 。每當(dāng) state 更新之后, view 會根據(jù) state 觸發(fā)重新渲染。
React-Redux:
Provider :從最外部封裝了整個應(yīng)用,并向 connect 模塊傳遞 store 。 Connect :
11、對高階組件的理解
高階組件是參數(shù)為組件,返回值為新組件的函數(shù)。 HOC 是純函數(shù),沒有副作用。 HOC 在 React 的第三方庫中很常見,例如 Redux 的 connect 組件。
高階組件的作用:
12、可以用哪些方式創(chuàng)建 React 組件?
React.createClass()、ES6 class 和無狀態(tài)函數(shù)
13、 React 元素與組件的區(qū)別?
組件是由元素構(gòu)成的。元素數(shù)據(jù)結(jié)構(gòu)是普通對象,而組件數(shù)據(jù)結(jié)構(gòu)是類或純函數(shù)。
Vue與React對比?
數(shù)據(jù)流:
react 主張函數(shù)式編程,所以推崇純組件,數(shù)據(jù)不可變,單向數(shù)據(jù)流,
vue 的思想是響應(yīng)式的,也就是基于是數(shù)據(jù)可變的,通過對每一個屬性建立Watcher來監(jiān)聽,當(dāng)屬性變化的時候,響應(yīng)式的更新對應(yīng)的虛擬dom。
監(jiān)聽數(shù)據(jù)變化實現(xiàn)原理 :
組件通信的區(qū)別:jsx和.vue模板。
性能優(yōu)化
vuex 和 redux 之間的區(qū)別?
從實現(xiàn)原理上來說,最大的區(qū)別是兩點:
Redux 使用的是不可變數(shù)據(jù),而 Vuex 的數(shù)據(jù)是可變的。 Redux 每次都是用新的 state 替換舊的 state ,而 Vuex 是直接修改
Redux 在檢測數(shù)據(jù)變化的時候,是通過 diff 的方式比較差異的,而 Vuex 其實和Vue的原理一樣,是通過 getter/setter 來比較的(如果看 Vuex 源碼會知道,其實他內(nèi)部直接創(chuàng)建一個 Vue 實例用來跟蹤數(shù)據(jù)變化)
瀏覽器從輸入url到渲染頁面,發(fā)生了什么?
網(wǎng)絡(luò)安全、HTTP協(xié)議
TCP UDP 區(qū)別
Http和Https區(qū)別(高頻)
GET和POST區(qū)別(高頻)
理解xss,csrf,ddos攻擊原理以及避免方式
XSS ( Cross-Site Scripting , 跨站腳本攻擊 )是一種代碼注入攻擊。攻擊者在目標(biāo)網(wǎng)站上注入惡意代碼,當(dāng)被攻擊者登陸網(wǎng)站時就會執(zhí)行這些惡意代碼,這些腳本可以讀取 cookie,session tokens ,或者其它敏感的網(wǎng)站信息,對用戶進行釣魚欺詐,甚至發(fā)起蠕蟲攻擊等。
CSRF ( Cross-site request forgery ) 跨站請求偽造 :攻擊者誘導(dǎo)受害者進入第三方網(wǎng)站,在第三方網(wǎng)站中,向被攻擊網(wǎng)站發(fā)送跨站請求。利用受害者在被攻擊網(wǎng)站已經(jīng)獲取的注冊憑證,繞過后臺的用戶驗證,達(dá)到冒充用戶對被攻擊的網(wǎng)站執(zhí)行某項操作的目的。
XSS避免方式:
CSRF 避免方式:
DDoS 又叫分布式拒絕服務(wù),全稱 Distributed Denial of Service ,其原理就是利用大量的請求造成資源過載,導(dǎo)致服務(wù)不可用。
這是來自richardrodger一篇博文,主要闡述微服務(wù)和模式匹配(消息),通過Node.js建立一個Http服務(wù)器作為微服務(wù),微服務(wù)之間通過消息傳遞,以微服務(wù)構(gòu)建模塊,進而模塊化構(gòu)建一個大型系統(tǒng)。原文大意如下:
Node.js能做大型系統(tǒng)嗎?回答是肯定的,沃爾瑪(Walmart)和Paypal的案例已經(jīng)證明,那么大型的Node.JS適合主流的開發(fā)者嗎?如果你認(rèn)為Node.js這樣的大型系統(tǒng)類似Java和.Net,那么你肯定認(rèn)為不行:javascript在支持復(fù)雜系統(tǒng)擴展性方面是一個弱性的語言。它不是強類型語言,而且有一半的語言是無法使用的。
盡管如此,我們已經(jīng)建立一些大型的NodeJS系統(tǒng),下面是我們的總結(jié):
傳統(tǒng)的主流的最大型的系統(tǒng)是龐大的鐵板一塊的monolithic,一個特別大的代碼庫,有很多文件,幾千個類無數(shù)個配置文件。如果在javascript中建立這樣的體制,可能會發(fā)瘋。那些將Node.js看成類似蜘蛛俠的人只會推崇使用Java和.NET建立龐大的系統(tǒng)。
鐵板一塊式monolithic系統(tǒng)是壞的
什么是鐵板一塊monolithic系統(tǒng),最簡單定義就是,你如果拿出來一部分,整體就會運行失敗,每個部分連接到其他部門,相互依存。這個詞也用來指一塊整石頭。
這個詞語來自古希臘,建筑直接在洛磯山的懸崖上鑿成,由于直接雕刻整個山,他們是無法修復(fù)的,城市最終陷入下降。軟件系統(tǒng)的復(fù)雜性隨著時間推移,難以修復(fù)和延伸,成本不斷提高。
鐵板一塊式的軟件產(chǎn)生的開發(fā)流程和方法危害更大,因為系統(tǒng)有這么多依賴,你必須關(guān)注如何讓開發(fā)者在改變它們時非常小心,大量精力用于防止代碼失敗。從瀑布到敏捷,都是為了鐵板一塊式的軟件服務(wù),都是為了讓軟件變得越來越大。遠(yuǎn)標(biāo)之前也講過這個問題
模塊化系統(tǒng)是好的
作為軟件開發(fā)者,應(yīng)該努力避免建立鐵板式系統(tǒng),那就是建立模塊化系統(tǒng),當(dāng)一個部分丟失時,整個系統(tǒng)還是可以運行。雖然像集裝箱那樣建立軟件的模塊化是一個很艱難的過程,但是我們知道這是處理復(fù)雜性的唯一方法。
對象是地獄
為實現(xiàn)模塊化系統(tǒng),面向?qū)ο蠓妒绞艿酵瞥?,其實對象比你想象中的要相差很多,他們來自天真的?shù)學(xué)觀點,是一種純柏拉圖的東西,以相同的屬性和特征劃分對象,表面上看合理,實際你在打破了現(xiàn)實世界的真實面貌,現(xiàn)實世界是混亂,甚至都打破了數(shù)學(xué)世界。請問集合是包含自身還是不包含自身呢(banq注:羅素的邏輯悖論)。
對象的最終弱點是,他們只是促成了向鐵板式龐大系統(tǒng)發(fā)展,對象只是一個系統(tǒng)需要的袋袋,什么都可以往里面裝,你有屬性,私有和公有,你有方法,也許覆蓋了其父類,你也可以有狀態(tài)。
有太多的東西可以裝入對象,結(jié)果一個巨大的類包含了最糾結(jié)最痛苦的大量邏輯。
NodeJs的模式是簡單的
有一個例子認(rèn)為計算斐波納契數(shù)是CPU密集型,而Node.js只有一個線程,那么計算斐波納契數(shù)的性能是可怕的。你可以使用異步委派到到操作系統(tǒng),使用processes 過程而不是線程處理,為了避免CPU密集型的計算,你需要將計算任務(wù)放入隊列,然后異步處理它們。
線程是出了名的難,Node.js的勝利就是避免了它們,你的代碼變得易懂。
有一個問題是在javascript中如何實現(xiàn)單例,實際上在現(xiàn)實中很少會碰到這種問題,因為模塊已經(jīng)幫你照看一切,最好的方式是你使用Node.js建立一個Server,通過網(wǎng)絡(luò)和其他部分通信。
NodeJS確實需要你學(xué)習(xí)一些新模式,主要是回調(diào)模式,回調(diào)函數(shù)的簽名有一個規(guī)律:如果有錯誤發(fā)生,第一個對象是錯誤對象,否則,第一個參數(shù)是空的,第二個總是返回的結(jié)果。
回調(diào)函數(shù)自然地來自Node.js的事件處理循環(huán), JavaScript最初用來處理瀏覽器中用戶界面事件,現(xiàn)在非常適合處理服務(wù)器端事件果。
當(dāng)你開始使用Node.js的第一件事就是創(chuàng)建回調(diào)(像意大利面條)。你結(jié)束了大量的縮進代碼,使用回調(diào)內(nèi)嵌回調(diào)。經(jīng)過一些練習(xí),你很快學(xué)會使用命名良好的函數(shù)結(jié)構(gòu)化你的代碼,包括異步模塊庫。
Node.js的另一個重大的模式是流,已經(jīng)被編寫成API,讓你輕松 簡潔操作和轉(zhuǎn)換數(shù)據(jù),你使用管道將數(shù)據(jù)從一個流接至另外一個惡瘤,你可以讀寫全雙工的數(shù)據(jù)流。
title: JS樹結(jié)構(gòu)數(shù)據(jù)的遍歷
date: 2022-04-14
description: 針對項目中出現(xiàn)樹形結(jié)構(gòu)數(shù)據(jù)的時候,我們怎樣去操作他
項目中我們會經(jīng)常出現(xiàn)對樹形結(jié)構(gòu)的遍歷、查找和轉(zhuǎn)換的場景,比如說DOM樹、族譜、社會機構(gòu)、組織架構(gòu)、權(quán)限、菜單、省市區(qū)、路由、標(biāo)簽等等。那針對這些場景和數(shù)據(jù),我們又如何去遍歷和操作,有什么方式或者技巧可以簡化我們的實現(xiàn)思路。下面我們將針對常規(guī)出現(xiàn)的場景去總結(jié)一下我們的遍歷方式
樹的特點
1、每個節(jié)點都只有有限個子節(jié)點或無子節(jié)點;
2、沒有父節(jié)點的節(jié)點稱為根節(jié)點;
3、每一個非根節(jié)點有且只有一個父節(jié)點;
4、除了根節(jié)點外,每個子節(jié)點可以分為多個不相交的子樹;
5、樹里面沒有環(huán)路
下面的圖片表示一顆樹
在下面的JS中我們由多棵樹組成我們的數(shù)據(jù)
在這數(shù)據(jù)中我們?nèi)绾卧u判數(shù)據(jù)是否為葉節(jié)點(也就是最后一級),我們每個節(jié)點都會存在children屬性,如果不存在children屬性或者children不是一個數(shù)組或者children為數(shù)組且長度為0我們則認(rèn)為他是一個葉節(jié)點
我們針對樹結(jié)構(gòu)的操作離不開遍歷,遍歷的話又分為廣度優(yōu)先遍歷、深度優(yōu)先遍歷。其中深度優(yōu)先遍歷可以通過遞歸和循環(huán)的方式實現(xiàn),而廣度優(yōu)先遍歷的話是非遞歸的
從上往下對每一層依次訪問,在每一層中,從左往右(也可以從右往左)訪問結(jié)點,訪問完一層就進入下一層,直到?jīng)]有結(jié)點可以訪問為止。即訪問樹結(jié)構(gòu)的第n+1層前必須先訪問完第n層。
簡單的說,BFS是從根節(jié)點開始,沿著樹的寬度遍歷樹的節(jié)點。如果所有節(jié)點均被訪問,則算法中止。
所以我們的實現(xiàn)思路是,維護一個隊列,隊列的初始值為樹結(jié)構(gòu)根節(jié)點組成的列表,重復(fù)執(zhí)行以下步驟直到隊列為空:
取出隊列中的第一個元素,進行訪問相關(guān)操作,然后將其后代元素(如果有)全部追加到隊列最后。
深度優(yōu)先搜索算法(英語:Depth-First-Search,DFS)是一種用于遍歷或搜索樹或圖的算法。這個算法會盡可能深的搜索樹的分支。當(dāng)節(jié)點v的所在邊都己被探尋過,搜索將回溯到發(fā)現(xiàn)節(jié)點v的那條邊的起始節(jié)點。這一過程一直進行到已發(fā)現(xiàn)從源節(jié)點可達(dá)的所有節(jié)點為止。如果還存在未被發(fā)現(xiàn)的節(jié)點,則選擇其中一個作為源節(jié)點并重復(fù)以上過程,整個進程反復(fù)進行直到所有節(jié)點都被訪問為止
1、先序遍歷
訪問子樹的時候,先訪問根再訪問根的子樹
2、后序遍歷
訪問子樹的時候,先訪問子樹再訪問根
1、先序遍歷
先序遍歷與廣度優(yōu)先循環(huán)實現(xiàn)類似,要維護一個隊列,不同的是子節(jié)點不追加到隊列最后,而是加到隊列最前面
2、后序遍歷
后序遍歷就略微復(fù)雜一點,我們需要不斷將子樹擴展到根節(jié)點前面去,執(zhí)行列表遍歷,并且通過一個臨時對象維護一個id列表,當(dāng)遍歷到某個節(jié)點如果它沒有子節(jié)點或者它本身已經(jīng)存在于我們的臨時id列表,則執(zhí)行訪問操作,否則繼續(xù)擴展子節(jié)點到當(dāng)前節(jié)點前面
對于樹結(jié)構(gòu)的遍歷操作,其實遞歸是最基礎(chǔ),也是最容易理解的。遞歸本身就是循環(huán)的思想,所以可以用循環(huán)來改寫遞歸,以上的方式在項目中已經(jīng)廊括了大部分的場景了,我們在日常開發(fā)中可以根據(jù)場景或者需要去選擇我們的遍歷方式,或者基于此對他進行調(diào)整和優(yōu)化,至于每種方式的空間復(fù)雜度和時間復(fù)雜度我們在這個地方就不去嘗試了,各位感興趣可以自己去驗證。
廣度優(yōu)先搜索
樹的遍歷
深度優(yōu)先搜索
圖文詳解兩種算法:深度優(yōu)先遍歷(DFS)和廣度優(yōu)先遍歷(BFS)
二叉樹遍歷(前序,后序,中序,層次)遞歸與迭代實現(xiàn)JavaScript
JS樹結(jié)構(gòu)操作:查找、遍歷、篩選、樹和列表相互轉(zhuǎn)換
從給定的數(shù)據(jù)中,隨機抽出一項,這項的左邊放所有比它小的,右邊放比它大的,然后再分別這兩邊執(zhí)行上述操作,采用的是遞歸的思想,總結(jié)出來就是 實現(xiàn)一層,分別給兩邊遞歸,設(shè)置好出口
function?fastSort(array,head,tail){
//考慮到給每個分區(qū)操作的時候都是在原有的數(shù)組中進行操作的,所以這里head,tail來確定分片的位置
/*生成隨機項*/
var?randomnum?=?Math.floor(ranDom(head,tail));
var?random?=?array[randomnum];
/*將小于random的項放置在其左邊??策略就是通過一個臨時的數(shù)組來儲存分好區(qū)的結(jié)果,再到原數(shù)組中替換*/
var?arrayTemp?=?[];
var?unshiftHead?=?0;
for(var?i?=?head;i?=?tail;i++){
if(array[i]random){
arrayTemp.unshift(array[i]);
unshiftHead++;
}else?if(array[i]random){
arrayTemp.push(array[i]);
}
/*當(dāng)它等于的時候放哪,這里我想選擇放到隊列的前面,也就是從unshift后的第一個位置放置*/
if(array[i]===random){
arrayTemp.splice(unshiftHead,0,array[i]);
}
}
/*將對應(yīng)項覆蓋原來的記錄*/
for(var?j?=?head?,?u=0;j?=?tail;j++,u++){
array.splice(j,1,arrayTemp[u]);
}
/*尋找中間項所在的index*/
var?nowIndex?=?array.indexOf(random);
/*設(shè)置出口,當(dāng)要放進去的片段只有2項的時候就可以收工了*/
if(arrayTemp.length?=?2){
return;
}
/*遞歸,同時應(yīng)用其左右兩個區(qū)域*/
fastSort(array,head,nowIndex);
fastSort(array,nowIndex+1,tail);
}
JavaScript實現(xiàn)多維數(shù)組、對象數(shù)組排序,其實用的就是原生的sort()方法,用于對數(shù)組的元素進行排序。
sort() 方法用于對數(shù)組的元素進行排序。語法如下:
arrayObject.sort(sortby)
例如:
function?NumAscSort(a,b)
{
return?a?-?b;
}
function?NumDescSort(a,b)
{
return?b?-?a;
}
var?arr?=?new?Array(?3600,?5010,?10100,?801);?
arr.sort(NumDescSort);
alert(arr);
arr.sort(NumAscSort);
alert(arr);