成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

校招社招必備核心前端面試問題與詳細(xì)解答

jonh_felix / 531人閱讀

摘要:本文總結(jié)了前端老司機(jī)經(jīng)常問題的一些問題并結(jié)合個(gè)人總結(jié)給出了比較詳盡的答案。網(wǎng)易阿里騰訊校招社招必備知識(shí)點(diǎn)。此外還有網(wǎng)絡(luò)線程,定時(shí)器任務(wù)線程,文件系統(tǒng)處理線程等等。線程核心是引擎。主線程和工作線程之間的通知機(jī)制叫做事件循環(huán)。

本文總結(jié)了前端老司機(jī)經(jīng)常問題的一些問題并結(jié)合個(gè)人總結(jié)給出了比較詳盡的答案。網(wǎng)易阿里騰訊校招社招必備知識(shí)點(diǎn)。
關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-你不知道的那些細(xì)節(jié)
課程知識(shí)在不斷更新,本片內(nèi)容也逐步更新
官方博客:FED123前端學(xué)堂

1.關(guān)于性能優(yōu)化說說js文件擺放順序、減少請(qǐng)求、雪碧圖等等原理, 說下window.performance.timing api是干什么的?

瀏覽器是按照文檔流解析html,為了更快構(gòu)建DOM樹和渲染樹將頁面呈現(xiàn)到屏幕上,建議是降js放在文檔dom樹結(jié)尾,body標(biāo)簽閉合前。
瀏覽器并發(fā)HTTP請(qǐng)求有限制(6個(gè)左右),加載頁面html后開始解析,解析到外鏈資源比如js css和圖片,就會(huì)發(fā)http請(qǐng)求獲取對(duì)應(yīng)資源。減少請(qǐng)求就是減少這些資源請(qǐng)求, 可以 css資源合并,js資源合并,圖片資源合并同時(shí)做lazyload,區(qū)分首屏非首屏接口,按需請(qǐng)求數(shù)據(jù)。
雪碧圖是一種圖片資源的合并方法,將一些小圖片合成一張圖,通過background-position來定位到對(duì)應(yīng)部分。
window.performance.timing 參考下前端頁面性能指標(biāo)數(shù)據(jù)計(jì)算方法, performance接口屬于w3c標(biāo)準(zhǔn)hight resolution time中的一部分,通過navigation timeline api 、 performance timeline api,user timing api,resource timeline api 這四個(gè)接口做了增強(qiáng)實(shí)現(xiàn)。其中navigation timeline api中PerformanceTiming?接口數(shù)據(jù)放在?performance.timing這個(gè)對(duì)象上。主要記錄了瀏覽器從跳轉(zhuǎn)開始的各個(gè)時(shí)間點(diǎn)的時(shí)間,比如navigationStart是頁面開始跳轉(zhuǎn)時(shí)間,fetchStart是頁面開始時(shí)間,domainLookupStart是DNS開始時(shí)間,domainLookupEnd是DNS結(jié)束時(shí)間, 查找到DNS后建立http鏈接,connectStart和connectEnd分別是鏈接開始和結(jié)束時(shí)間,然后是requestStart開始發(fā)起請(qǐng)求時(shí)間,responseStart開始響應(yīng)時(shí)間,responseEnd響應(yīng)結(jié)束時(shí)間。然后是茍安DOM樹時(shí)間,分別是domLoading, domInteractive, domContentLoad和domComplete時(shí)間,分別對(duì)應(yīng)document.readyState狀態(tài)loading、interactive和complete。最后是頁面onload,分別是loadEventStart和loadEventEnd時(shí)間節(jié)點(diǎn)。

可以通過這個(gè)接口統(tǒng)計(jì)前端的頁面性能數(shù)據(jù)。

domainLookupStart -?fetchStart = appCache時(shí)間,這段時(shí)間瀏覽器首先檢查緩存
domainLookupEnd -domainLookupStart = DNS時(shí)間
connectEnd - connectStart = TCP時(shí)間
responseStart - requestStart = FTTB首字節(jié)時(shí)間,或者說是服務(wù)器響應(yīng)等待時(shí)間
domContentLoad -?navigationStart = 頁面pageLoad時(shí)間
?loadEventEnd -?navigationStart = 頁面onLoad時(shí)間

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

2.請(qǐng)你描述下一個(gè)網(wǎng)頁是如何渲染出來的,dom樹和css樹是如何合并的,瀏覽器的運(yùn)行機(jī)制是什么,什么是否會(huì)造成渲染阻塞?

參考下:瀏覽器工作原理???瀏覽器渲染與阻塞原理

第一部分通過performance.time這個(gè)api我們可以了解瀏覽器加載網(wǎng)頁的流程,瀏覽器邊加載html邊構(gòu)建DOM樹,當(dāng)然會(huì)有容錯(cuò)和修正機(jī)制。瀏覽器解析到行內(nèi)css和內(nèi)聯(lián)css會(huì)立馬加入到構(gòu)建渲染樹,解析到外鏈css就開始加載,加載完之后也會(huì)合并到渲染樹的構(gòu)建中,最后將渲染樹和DOM做節(jié)點(diǎn)鏈路匹配,也叫l(wèi)ayout階段,計(jì)算每個(gè)DOM元素最終在屏幕上顯示的大小和位置。 遍歷順序?yàn)閺淖笾劣?,從上到下,繪制在屏幕上,layout過程中可能會(huì)觸發(fā)頁面回流和重繪,比如某個(gè)外鏈css加載完解析之后合并構(gòu)建到渲染樹中,其中某個(gè)css改變了DOM樹種某個(gè)元素的定位(改成絕對(duì)定位)或者改變了長(zhǎng)寬邊距等位置信息,會(huì)觸發(fā)重新layout,所以會(huì)回流reflow。重繪是比如css改變了之前的背景圖片顏色,瀏覽器會(huì)重新繪制。

會(huì)有渲染阻塞,瀏覽器刷新的頻率大概是60次/秒, 也就是說刷新一次大概時(shí)間為16ms,如果瀏覽器對(duì)每一幀的渲染工作超過了這個(gè)時(shí)間, 頁面的渲染就會(huì)出現(xiàn)卡頓的現(xiàn)象。瀏覽器內(nèi)核中有3個(gè)最主要的線程:JS線程,UI渲染線程,事件處理線程。此外還有http網(wǎng)絡(luò)線程,定時(shí)器任務(wù)線程,文件系統(tǒng)處理線程等等。

JS線程負(fù)責(zé)JS代碼解析編譯執(zhí)行,稱為主線程。常說‘瀏覽器是單線程’指的是JS主線程只能有一個(gè),主線程執(zhí)行同步任務(wù),會(huì)阻塞UI渲染線程。JS線程核心是js引擎 (IE9+: Chakra firefox:monkey chrome:v8)。webworker可以創(chuàng)建多個(gè)js線程,但是受主線程控制,主要用于cpu密集型計(jì)算。
UI渲染線程當(dāng)然是負(fù)責(zé)構(gòu)建渲染樹,執(zhí)行頁面元素渲染。核心是渲染引擎(firefox:gecko、chrome/safari:webkit),由于JS可以操作DOM元素處理樣式等,JS主線程是執(zhí)行同步任務(wù)的,所以設(shè)計(jì)上JS引擎線程和GUI渲染線程是互斥的。 也就是說JS引擎處于運(yùn)行狀態(tài)時(shí),GUI渲染線程將處于凍結(jié)狀態(tài)。
事件處理線程,由于瀏覽器是事件驅(qū)動(dòng)的,事件處理線程用來控制事件回調(diào)處理,瀏覽器觸發(fā)某個(gè)事件后會(huì)把事件回調(diào)函數(shù)放到任務(wù)隊(duì)列中,可以看下下面會(huì)提到。
其他線程統(tǒng)稱工作線程,如處理 ajax 的線程,dom事件線程、定時(shí)器線程、讀寫文件的線程等,工作線程的任務(wù)完成之后, 會(huì)推入到一個(gè)任務(wù)隊(duì)列(task queue)

總結(jié)一下,渲染阻塞有兩個(gè)方面:

js主線程執(zhí)行時(shí)間長(zhǎng)會(huì)導(dǎo)致渲染線程阻塞,影響渲染。我們也稱為longtask
渲染線程自身阻塞,渲染時(shí)間達(dá)不到幀率60,會(huì)看起來卡頓,比如回流或者重繪等,或者css效率太低,動(dòng)畫處理不合適,導(dǎo)致渲染耗時(shí)
3.請(qǐng)簡(jiǎn)述下js引擎的工作原理,js是怎樣處理事件的eventloop,宏任務(wù)源tasks和微任務(wù)源jobs分別有哪些?js是如何構(gòu)造抽象語法樹(AST)的?

js引擎只執(zhí)行同步任務(wù), 異步任務(wù)會(huì)有工作線程來執(zhí)行,當(dāng)需要進(jìn)行異步操作(定時(shí)器、ajax請(qǐng)求、dom事件注冊(cè)等), 主線程會(huì)發(fā)一個(gè)異步任務(wù)的請(qǐng)求, 相應(yīng)的工作線程接受請(qǐng)求; 當(dāng)工作線程完成工作之后, 通知主線程;主線程接收到通知之后, 會(huì)執(zhí)行一定的操作(回調(diào)函數(shù))。主線程和工作線程之間的通知機(jī)制叫做事件循環(huán)。

調(diào)用棧 (call stack): 主線程執(zhí)行時(shí)生成的調(diào)用棧
任務(wù)隊(duì)列 (task queue): 工作線程完成任務(wù)后會(huì)把消息推到一個(gè)任務(wù)隊(duì)列, 消息就是注冊(cè)時(shí)的回調(diào)函數(shù)

當(dāng)調(diào)用棧為空時(shí), 主線程會(huì)從任務(wù)隊(duì)列里取一條消息并放入當(dāng)前的調(diào)用棧當(dāng)中執(zhí)行, 主線程會(huì)一直重復(fù)這個(gè)動(dòng)作直到消息隊(duì)列為空。 這個(gè)過程就叫做事件循環(huán) (event-loop)。

關(guān)于宏任務(wù)和微任務(wù),參考?事件流、事件模型、事件循環(huán)概念理解??瀏覽器線程理解與microtask與macrotask

ES6新引入了Promise標(biāo)準(zhǔn),同時(shí)瀏覽器實(shí)現(xiàn)上多了一個(gè)microtask微任務(wù)概念。在ECMAScript中,microtask稱為jobs,macrotask可稱為task。

macrotask宏任務(wù)tasks,也就是上面說到的任務(wù)隊(duì)列的任務(wù)。執(zhí)行棧上的每個(gè)任務(wù)都屬于宏任務(wù),主線程執(zhí)行完執(zhí)行棧的任務(wù),從任務(wù)隊(duì)列取新的任務(wù)。宏任務(wù)執(zhí)行時(shí)不會(huì)中斷,會(huì)一次性執(zhí)行完,為了及時(shí)渲染數(shù)據(jù),主線程執(zhí)行完一個(gè)宏任務(wù)之后,會(huì)執(zhí)行一次渲染。

task--》渲染 --》宏任務(wù) --》渲染? .....

microtask微任務(wù)jobs,可以看成是插隊(duì)需要及時(shí)處理的任務(wù),會(huì)在當(dāng)前主線程task任務(wù)執(zhí)行后,渲染線程渲染之前,執(zhí)行完當(dāng)前積累所有的微任務(wù)。

task--》jobs --》渲染 --》宏任務(wù) --》jobs --》渲染? .....

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端
AST 參考:程序語言進(jìn)階之DSL與AST實(shí)戰(zhàn)解析

將抽象語法樹之前要先了解下NLP中文法的概率。任何一種語言,具體說就是DSL,都有自己的一套文法,用來表示這套語言的邏輯規(guī)范。不同的文法寫出來的語法表達(dá)式也不一樣。我們根據(jù)語法表達(dá)式來解析語言,就可以形成一個(gè)AST抽象語法樹。然后可以作進(jìn)一步處理。我常用的是PEG解析表達(dá)式語法。可以很輕松的寫出語法的每一條產(chǎn)生式規(guī)則,來構(gòu)造生成AST。所謂AST可以理解成按照一定語法結(jié)構(gòu)組成的詞匯流,每個(gè)詞匯有特定的語法含義,比如說這是一個(gè)聲明,這個(gè)一個(gè)操作符等等。

上面這個(gè)圖是蘋果最早做的KHTML渲染引擎中的KJS(javascript引擎),他是基于AST來實(shí)現(xiàn)的JavaScript語言解析的,先通過詞法分析得到JSTokens流,然后經(jīng)過語法分析得到抽象語法樹,然后經(jīng)過字節(jié)碼生成器,轉(zhuǎn)換成字節(jié)碼。字節(jié)碼經(jīng)過JavaScript虛擬機(jī)JIT編譯成機(jī)器碼,然后執(zhí)行。這是最初的設(shè)計(jì)架構(gòu),后來蘋果公司基于此重構(gòu)出了webkit渲染引擎,google基于webkit多帶帶維護(hù),稱為blink渲染引擎,chrome的JS引擎改造為V8引擎。參考:簡(jiǎn)述Chromium, CEF, Webkit, JavaScriptCore, V8, Blink

舉個(gè)例子常用的babel插件的原理就是基于babylon詞法語法分析器生成抽象語法樹,將代碼文本轉(zhuǎn)換成按照特定語法組合的token流集合,然后經(jīng)過babtlon-traverse這個(gè)組件來負(fù)責(zé)處理遍歷語法樹,訪問每個(gè)token節(jié)點(diǎn),通過對(duì)token的處理,可以生成我們需要的AST語法樹,然后再通過babylon-generator這個(gè)組件來做代碼生成,根據(jù)AST生成代碼。比如可以將 箭頭函數(shù) 轉(zhuǎn)換成 function函數(shù)。

瀏覽器中,通過開發(fā)者調(diào)試工具分析就能看到,下載完js腳本后,首先瀏覽器要先解析代碼=》初始化上下文環(huán)境=》執(zhí)行代碼,整個(gè)是evaluate script的過程,解析代碼的過程也是編譯js的過程所以看最前面第一步就是compile script,將js代碼編譯成字節(jié)碼(這一塊涉及到瀏覽器js引擎的優(yōu)化,v8引擎是編譯成字節(jié)碼,后面經(jīng)過JIT解析執(zhí)行(這個(gè)參考 你不知道的LLVM編譯器?可以提升效率做動(dòng)態(tài)優(yōu)化), 這個(gè)類似于java、C#這些需要將源代碼編譯成中間語言,然后在虛擬機(jī)執(zhí)行,javascript編譯成字節(jié)碼后面也是在虛擬機(jī)執(zhí)行),然后就開始執(zhí)行腳本。

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

4.你是否考慮全面你編寫的整個(gè)函數(shù),或者整個(gè)功能的容錯(cuò)性與擴(kuò)展性?怎樣構(gòu)建一個(gè)組件是最合理最科學(xué)的,對(duì)于錯(cuò)誤的處理是否有統(tǒng)一的方式方法?

擴(kuò)展性主要是從功能上考慮,容錯(cuò)性是從數(shù)據(jù)上考慮。

設(shè)計(jì)開發(fā)組件的時(shí)候首先要設(shè)計(jì)好數(shù)據(jù)模型,當(dāng)然可以和后端共同約定一個(gè)標(biāo)準(zhǔn),后面只要是這部分都用這個(gè)標(biāo)準(zhǔn)字段。后面可以對(duì)標(biāo)準(zhǔn)字段做擴(kuò)展,開發(fā)時(shí)候要做容錯(cuò)和數(shù)據(jù)響應(yīng)式開發(fā)。
功能這部分其實(shí)可以從基礎(chǔ)功能和擴(kuò)展功能來看,基礎(chǔ)功能可以在原有組件上做根據(jù)數(shù)據(jù)來展示。擴(kuò)展功能可以通過組件結(jié)合的形式來處理。

我主要考慮的是組件復(fù)用,可以將一類組件歸類,比如商品卡片,基本都是頭圖加標(biāo)題行動(dòng)點(diǎn),價(jià)格,按鈕。這就是最基礎(chǔ)的一個(gè)組件。擴(kuò)展性可以通過數(shù)據(jù)來做響應(yīng)式的展示,比如新增一個(gè)描述,數(shù)據(jù)模型新增描述字段,有描述字段卡片上就展示描述,沒有就不展示。像點(diǎn)擊按鈕的加購(gòu)功能可以多帶帶做成功能組件,統(tǒng)一處理,而不放在卡片上。因?yàn)檫@種加購(gòu)?fù)綆У氖巧虡I(yè)邏輯,有很多業(yè)務(wù)邏輯要處理,獨(dú)立出來反而更利于維護(hù)和拓展。

錯(cuò)誤處理我們這邊是基于組件的方式來處理,開發(fā)一個(gè)錯(cuò)誤處理的功能組件,提供thenable的能力,區(qū)分不同的錯(cuò)誤類型,提供統(tǒng)一埋點(diǎn)做監(jiān)控和記錄。

5.瀏覽器緩存的基本策略,什么時(shí)候該緩存什么時(shí)候不該緩存,以及對(duì)于控制緩存的字段的相關(guān)設(shè)置是否清楚?

參考下:HTTP協(xié)商緩存VS強(qiáng)緩存原理

前面介紹navigation api時(shí)候介紹了瀏覽器加載頁面的各個(gè)關(guān)鍵時(shí)間節(jié)點(diǎn)。和緩存相關(guān)的主要有兩部分

appcache,這部分是離線緩存,在fetchStart和domainLookupStart之間,這部分參考whatwg標(biāo)準(zhǔn)已經(jīng)棄用,建議用serviceworker。這里也不做介紹。
HTTP緩存這部分是在requestStart開始,發(fā)起資源http請(qǐng)求開始,這部分涉及到強(qiáng)緩存和協(xié)商緩存。瀏覽器對(duì)于請(qǐng)求過得資源會(huì)緩存下來請(qǐng)求的響應(yīng)數(shù)據(jù),后面請(qǐng)求時(shí)會(huì)先從緩存查找匹配的請(qǐng)求的響應(yīng)頭,如果命中強(qiáng)緩存(判斷cache-control和expires信息)那么直接從緩存獲取響應(yīng)數(shù)據(jù),不會(huì)再發(fā)送http請(qǐng)求。如果沒有命中瀏覽器會(huì)發(fā)送請(qǐng)求到服務(wù)器,同時(shí)會(huì)攜帶第一次請(qǐng)求的響應(yīng)頭的緩存相關(guān)header字段(last-modified/if-modified-since, Etag/if-none-match), 服務(wù)端根據(jù)這些請(qǐng)求頭判斷是否走緩存,如果走緩存,服務(wù)端會(huì)返回新的響應(yīng)頭,但不返回?cái)?shù)據(jù),瀏覽器會(huì)更新響應(yīng)頭,從緩存拿數(shù)據(jù)。如果不走緩存,服務(wù)端就會(huì)返回新的響應(yīng)頭和數(shù)據(jù),然后瀏覽器更新緩存的數(shù)據(jù)。

-》強(qiáng)緩存,判斷依據(jù)是expires(http 1.0協(xié)議規(guī)定)和cache-control(http 1.1協(xié)議規(guī)定)字段,expires是絕對(duì)時(shí)間,cache-control有可選值no-cache(不使用本地緩存,走協(xié)商緩存),no-store(禁止瀏覽器緩存數(shù)據(jù),每次都是重新獲取數(shù)據(jù)),public(可以被客戶端和中間商CDN做緩存),private(只能客戶端緩存,CDN不能緩存)

-》協(xié)商緩存,用到的響應(yīng)頭字段是last-modified/if-modified-since, Etag/if-none-match,這是兩對(duì)哈,每隊(duì)/前面一個(gè)是服務(wù)端返回的response header中的字段,/后面是請(qǐng)求頭request攜帶的頭部字段,第一次請(qǐng)求資源瀏覽器會(huì)返回last-modified(最后修改時(shí)間),后面再次請(qǐng)求請(qǐng)求頭會(huì)帶上if-modified-since,當(dāng)然這個(gè)值和上次瀏覽器返回的last-modified是一樣的,然后瀏覽器判斷如果文件沒有變化,那么返回304?Not Modified http code,響應(yīng)請(qǐng)求頭不會(huì)攜帶last-modified字段,瀏覽器從緩存取數(shù)據(jù),也不用更新last-modified字段,如果有修改,那么響應(yīng)頭返回新的last-modified字段數(shù)據(jù),返回響應(yīng)內(nèi)容。Etag/if-none-match這一對(duì)是同樣的邏輯,不同之處是用etag標(biāo)識(shí)來判斷文件是否修改,而不是用時(shí)間,因?yàn)榉?wù)器時(shí)間可能會(huì)變的,還會(huì)收到時(shí)區(qū)的影響。還有一點(diǎn)是每次請(qǐng)求都會(huì)返回etag字段,即使沒有變化。

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

6.你是否可以利用面向?qū)ο蟮乃季S去抽象你的功能,你會(huì)構(gòu)建一個(gè)class(ES6)嗎?你對(duì)于前端架構(gòu)的理解?

我目前開發(fā)分情況用不同的技術(shù)框架。

如果單純開發(fā)導(dǎo)購(gòu)頁面,比如一個(gè)商品列表頁面,這種為了加載性能和操作體驗(yàn),我是不考慮用框架的,也不用class,單純用自己開發(fā)的原生ES框架自己控制頁面模塊生命周期,基于函數(shù)式編程寫stateless組件。盡量減少?gòu)?fù)雜度,簡(jiǎn)單化。
如果是開發(fā)功能性組件,我是會(huì)用面型對(duì)象的模式來做開發(fā)。面向?qū)ο蟮暮诵氖欠庋b、繼承、多態(tài)。封裝就是將具體化為抽象,抽象成class,封裝抽象出來的屬性和方法。繼承是因?yàn)槌橄罂梢杂袑蛹?jí),比如對(duì)異常處理,參數(shù)異??梢猿橄蟪梢活悾瑺顟B(tài)異??梢猿橄蟪梢活悾瑓?shù)異常和狀態(tài)異常有共通的地方,比如結(jié)構(gòu)上都會(huì)返回異常的名稱和描述,這就可以抽象一層公共父類,然后這兩個(gè)異常繼承自公共父類,這就是集成。多態(tài)也是隨著繼承而來的,比如參數(shù)異常和狀態(tài)異常都繼承了name這個(gè)屬性,都可以實(shí)現(xiàn)對(duì)應(yīng)的get方法,但是他們的實(shí)現(xiàn)結(jié)果可定是不一樣的,根據(jù)自身類的抽象來實(shí)現(xiàn),調(diào)用的時(shí)候調(diào)用同樣的方法也就有不同的表現(xiàn)。比如參數(shù)異常和狀態(tài)異常都繼承了toString的方法,在調(diào)用各自的實(shí)例的toString方法時(shí),輸出的數(shù)據(jù)是不一樣的。另外設(shè)計(jì)的2大原則是:?jiǎn)我宦氊?zé)原則和開放封閉原則。單一職責(zé)只是抽象的類盡量保持功能專一,開閉原則指設(shè)計(jì)的時(shí)候要考慮好擴(kuò)展,對(duì)修改關(guān)閉,對(duì)擴(kuò)展開放。

export class RuntimeException {

    constructor(message) {
        this._message = message;
    }

    get name() {
        return "RuntimeException";
    }

    get message() {
        return this._message;
    }

    toString() {
        return this.name + ": " + this.message;
    }

}

export class IllegalStateException extends RuntimeException {

    constructor(message) {
        super(message);
    }

    get name() {
        return "IllegalStateException";
    }

}

export class InvalidArgumentException extends RuntimeException {

    constructor(message) {
        super(message);
    }

    get name() {
        return "InvalidArgumentException";
    }

}

export class NotImplementedException extends RuntimeException {

    constructor(message) {
        super(message);
    }

    get name() {
        return "NotImplementedException";
    }

}

對(duì)于前端領(lǐng)域來說,目前前端框架做掉了很多事情,搭建好項(xiàng)目框架之后,開發(fā)的就行就是填功能。所編寫的模塊和組件的模式也比較固定,可以根據(jù)具體情況來實(shí)現(xiàn)。

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

7.你會(huì)用VUE,你會(huì)用React,你讀得懂這兩個(gè)架構(gòu)的源碼嗎?你懂他倆的基本設(shè)計(jì)模式嗎?讓你去構(gòu)建一個(gè)類似的框架你如何下手?

angular

特點(diǎn): 數(shù)據(jù)雙向綁定-》數(shù)據(jù)驅(qū)動(dòng)開發(fā)的思想
html標(biāo)簽化的模板,模塊化思想
數(shù)據(jù)綁定,控制器,依賴注入,
服務(wù),指令,過濾器…

優(yōu)點(diǎn): 比較完善規(guī)范,文檔、社區(qū)比較活躍
模塊清晰,代碼明了

缺點(diǎn): 功能規(guī)范太固定,開發(fā)發(fā)揮空間小。
相對(duì)react和vue,不夠輕量化
擴(kuò)展性不夠靈活

react
特點(diǎn): 強(qiáng)大的組件化思想,任意封裝、組合
獨(dú)創(chuàng)JSX語法,virtual dom智能patch,靈活高效
輕量,易擴(kuò)展,模塊清晰,代碼明了
社區(qū)生態(tài)完善,組件庫(kù)、插件庫(kù)豐富
新特性: hooks,錯(cuò)誤邊界等優(yōu)化

缺點(diǎn): 組件難以在復(fù)雜交互場(chǎng)景復(fù)用
側(cè)重于做組件,做view展示層,對(duì)于業(yè)務(wù)邏輯等封裝治理不如angular強(qiáng)大
JSX中html模板不夠完備和健壯,比如一些屬性變換寫法,綁定事件大小寫

vue
特點(diǎn): 文檔豐富,容易上手
模板較完備,聲明式渲染,插值表達(dá)式與指令系統(tǒng),
事件處理器,修飾符,計(jì)算屬性?,簡(jiǎn)單易用,功能強(qiáng)
社區(qū)生態(tài)完善,組件庫(kù)、插件庫(kù)豐富

缺點(diǎn): 輕量框架使用是要結(jié)合生態(tài)插件組件使用,項(xiàng)目初始配置比較麻煩,
不過可以參考各種場(chǎng)景的標(biāo)準(zhǔn)模板配置,很多腳手架

聲明式渲染與命令式渲染:? 這個(gè)涉及到函數(shù)式編程中的一個(gè)聲明式編程和命令式編程的概念。
比如命令式編程:

let a = []
for(let i=0; i< 10; i++){
  a.push(i*10)
}

聲明式編程:

let a = []
arr.forEach(i=>{
  a.push(i*10)
})

聲明式編程隱藏了函數(shù)處理細(xì)節(jié),命令式編程則需要處理細(xì)節(jié)。

聲明式編程的好處是簡(jiǎn)單化,易于理解,減少勞動(dòng)量。比如vue中的指令綁定事件,綁定屬性都是這樣。@click,:title等等,用的時(shí)候很方便,這正是聲明式編程最直觀的好處。

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

8.你了解的ES6只是const、let、promise嗎?你考慮過ES6提出的真正趨勢(shì)嗎?

怎么可能,我又不是你。ES6中最常用的像變量定義這部分用let、const可以避免一些坑,異步處理可以用promise,不過我到喜歡用async/await 更簡(jiǎn)潔好用。

還有簡(jiǎn)寫的箭頭函數(shù),代碼看起來更清晰。
"..." 變量析構(gòu)和組裝, 函數(shù)默認(rèn)值
``模板字符串,便于字符拼接;標(biāo)簽?zāi)0?功能
Object對(duì)象的擴(kuò)展, for in, Object.keys
Set和Map
class和module相關(guān)

發(fā)展趨勢(shì): 總體來說前端開發(fā)更規(guī)范,更簡(jiǎn)單,語法更完備和成熟。支持的功能增強(qiáng),開發(fā)效率提升,體驗(yàn)增強(qiáng)。

ES6的模塊化相關(guān)支持,可以更好地支持模塊化開發(fā)。
原生支持class,面向?qū)ο蟮木幊蹋拍罡菀桌斫?,易于軟件開發(fā)和集成。
異步操作規(guī)范化,異步編程更簡(jiǎn)單

9.你會(huì)用less,那么讓你去寫一個(gè)loader你可以嗎?

參考下:程序語言進(jìn)階之DSL與AST實(shí)戰(zhàn)解析

可以的,說一下原理,需要將 .less 文件最終解析成CSS,less是一種DSL,我們可以現(xiàn)根據(jù)less預(yù)發(fā),先將其解析成AST,然后解析成CSS即可。 我推薦用PEG.js這種解析表達(dá)式語法更簡(jiǎn)單些,只需要描述產(chǎn)生式規(guī)則即可。也可以自己根據(jù)LESS預(yù)發(fā)來寫正則表達(dá)來匹配規(guī)則,然后轉(zhuǎn)換成css。比較常用的是PostCSS,處理流程如下:參考官方文檔

PostCSS的處理流程也是經(jīng)過詞法解析語法分析,將讀取到的文件字符轉(zhuǎn)化成詞匯流tokens,根據(jù)語法分析,根據(jù)less的語法,解析成一個(gè)AST。

source string → tokens → AST

核心組件有:

詞法分析器 Tokenizer (?lib/tokenize.es6?)
語法分析器 Parser (?lib/parse.es6,?lib/parser.es6?)
插件處理器 Processor (?lib/processor.es6?)
代碼生成器 Stringifier (?lib/stringify.es6,?lib/stringifier.es6?)

10.webpack你也會(huì)用,你了解其中原理嗎?你知道分析打包依賴的過程嗎?你知道tree-shaking是如何干掉無用重復(fù)的代碼的嗎?

大家之前應(yīng)該用過gulp,grunt這種代碼打包工具,定義不同的打包任務(wù)和打包流程。我用的比較多的rollup這個(gè)打包工具,配置起來比較簡(jiǎn)單些。

webpack也是用來做代碼打包,可以做代碼分析,拆分,混淆,壓縮等等,基于他的插件擴(kuò)展機(jī)制可以做很多事情。分析webpack的原理,可以先從webpack配置文件說起。參考:webpack編譯代碼原理介紹?用webpack4和一些插件提升代碼編譯速度

首先作為打包工具,要定義打包的輸入entry和輸出output;然后是定義webpack要用到的module,比如babel js loader, cssloader等等。執(zhí)行編譯具體的流程是:

加載webpack配置文件 --》 根據(jù)配置初始化編譯器compiler --》找到入口,根據(jù)loader配置開始編譯入口文件以及層層依賴 --》編譯完成之后,可以得到所有編譯過的文件和依賴關(guān)系結(jié)構(gòu) --》根據(jù)依賴關(guān)系將模塊組裝成一個(gè)個(gè)包含多個(gè)模塊的chunk,然后根據(jù)配置寫到輸出文件。

webpack構(gòu)建流程可分為以下三大階段。

初始化:?jiǎn)?dòng)構(gòu)建,讀取與合并配置參數(shù),加載plugin,實(shí)例化Compiler
編譯:從Entry出發(fā),針對(duì)每個(gè)Module串行調(diào)用對(duì)應(yīng)的Loader去翻譯文件中的內(nèi)容,再找到該Module依賴的Module,遞歸的進(jìn)行編譯處理
輸出:將編譯后的Module組合成Chunk,將Chunk轉(zhuǎn)換成文件,輸出到文件系統(tǒng)中

分析依賴是在編譯過程中完成的,從入口查找依賴,最后形成依賴關(guān)系。 為了提高效率,可以記錄分析過的依賴,這樣下次遇到同樣的模塊就不用再分析,直接引用編譯過的依賴就可以了。

tree-shaking的名字原理一樣,就是搖一搖大樹,落下來的葉子都是冗余的部分。Tree-shaking 較早由 Rich_Harris 的 rollup 實(shí)現(xiàn),后來,webpack2 也增加了tree-shaking 的功能。其實(shí)在更早,google closure compiler 也做過類似的事情。三個(gè)工具的效果和使用各不相同,使用方法可以通過官網(wǎng)文檔去了解。

tree shaking的目的是去掉無用代碼,減少代碼體積。其實(shí)對(duì)于編譯的編程語言對(duì)應(yīng)的編譯器基本都有判斷哪些代碼不會(huì)影響輸出,從而在編譯時(shí)移除這些代碼的功能,稱為DCE(dead code elimination)。tree shaking 是DCE的一種實(shí)現(xiàn),傳統(tǒng)的是消除沒有引用不會(huì)執(zhí)行的代碼,tree shaking 主要是要消除沒有用的代碼。

Dead Code 一般具有以下幾個(gè)特征

?代碼不會(huì)被執(zhí)行,不可到達(dá)

?代碼執(zhí)行的結(jié)果不會(huì)被用到

?代碼只會(huì)影響死變量(只寫不讀)

在前端代碼打包處理中,最終都會(huì)有個(gè)代碼壓縮混淆的環(huán)節(jié),這個(gè)環(huán)節(jié)其實(shí)會(huì)完成DCE的工作,會(huì)將這些dead code移除。

但是uglify代碼是只是單個(gè)單個(gè)文件處理,并不能分析出這個(gè)代碼有沒有被其他文件用到,當(dāng)然也不會(huì)對(duì)這些為被調(diào)用的函數(shù)做處理,如上圖uglify就不會(huì)去除沒用到的get函數(shù),所以就需要tree shaking。tree shaking是有限制的,只能消除函數(shù)和import/export的變量,不會(huì)處理import/export的class(因?yàn)閖avascript動(dòng)態(tài)語言特性使得分析比較困難,可能導(dǎo)致以外的錯(cuò)誤,side effect比較大), 對(duì)于純函數(shù)處理效果較好。
關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

11.你真的熟練使用css嗎,那你知道position有幾個(gè)屬性嗎

具體參考https://github.com/wintercn/b...

static:無特殊定位,對(duì)象遵循正常文檔流。top,right,bottom,left等屬性不會(huì)被應(yīng)用。
relative:對(duì)象遵循正常文檔流,但將依據(jù)top,right,bottom,left等屬性在正常文檔流中偏移位置,相對(duì)定位相對(duì)的是它原本在文檔流中的位置而進(jìn)行的偏移。而其層疊通過z-index屬性定義。占據(jù)的文檔空間不會(huì)隨 top / right / left / bottom 等屬性的偏移而發(fā)生變動(dòng),也就是說它后面的元素是依據(jù)( top / left / right / bottom 等屬性生效之前)進(jìn)行的定位,這點(diǎn)一定要理解。
absolute:對(duì)象脫離正常文檔流,使用top,right,bottom,left等屬性進(jìn)行絕對(duì)定位。而其層疊通過z-index屬性定義。使用absoulte或fixed定位的話,必須指定 left、right、 top、 bottom 屬性中的至少一個(gè),否則left/right/top/bottom屬性會(huì)使用它們的默認(rèn)值 auto ,這將導(dǎo)致對(duì)象遵從正常的HTML布局規(guī)則,在前一個(gè)對(duì)象之后立即被呈遞,簡(jiǎn)單講就是都變成relative,會(huì)占用文檔空間,這點(diǎn)非常重要,很多人使用absolute定位后發(fā)現(xiàn)沒有脫離文檔流就是這個(gè)原因。
fixed:對(duì)象脫離正常文檔流,使用top,right,bottom,left等屬性以窗口為參考點(diǎn)進(jìn)行定位,當(dāng)出現(xiàn)滾動(dòng)條時(shí),對(duì)象不會(huì)隨著滾動(dòng)。而其層疊通過z-index屬性定義。
sticky:?The element is positioned according to the normal flow of the document, and then offset relative to its?nearest scrolling ancestor?and?containing block?(nearest block-level ancestor), including table-related elements, based on the values of?top,?right,?bottom, and?left. The offset does not affect the position of any other elements.This value always creates a new?stacking context. Note that a sticky element "sticks" to its nearest ancestor that has a "scrolling mechanism" (created when?overflow?is?hidden,?scroll,?auto, or?overlay), even if that ancestor isn"t the nearest actually scrolling ancestor. This effectively inhibits any "sticky" behavior (see the?Github issue on W3C CSSWG).

absolute就只能根據(jù)祖先類元素(父類以上)進(jìn)行定位,而這個(gè)祖先類還必須是以postion非static方式定位的, 舉個(gè)例子,a元素使用absoulte定位,它會(huì)從父類開始找起,尋找以position非static方式定位的祖先類元素(注意,一定要是直系祖先才算哦~),直到標(biāo)簽為止,這里還需要注意的是,relative和static方式在最外層時(shí)是以標(biāo)簽為定位原點(diǎn)的,而absoulte方式在無父級(jí)是position非static定位時(shí)是以作為原點(diǎn)定位。

參考:?position屬性

關(guān)于Layout and the containing block,看下官方介紹的contain block,另外相關(guān)的點(diǎn)是 BFC:如何創(chuàng)建塊級(jí)格式化上下文(block formatting context),BFC有什么用

12 前端動(dòng)畫渲染機(jī)制了解嗎?硬件加速原理?

參考:瀏覽器渲染流水線解析與網(wǎng)頁動(dòng)畫性能優(yōu)化

動(dòng)畫可以看做是一個(gè)連續(xù)的幀序列的組合。我們把網(wǎng)頁的動(dòng)畫分成兩大類 —— 一類是合成器動(dòng)畫,一類是非合成器動(dòng)畫(UC 內(nèi)部也將其稱為內(nèi)核動(dòng)畫或者 Blink Animation,雖然這不是 Chrome 官方的術(shù)語)。

合成器動(dòng)畫顧名思義,動(dòng)畫的每一幀都是由 Layer Compositor 生成并輸出的,合成器自身驅(qū)動(dòng)著整個(gè)動(dòng)畫的運(yùn)行,在動(dòng)畫的過程中,不需要新的 Main Frame 輸入;
非合成器動(dòng)畫,每一幀都是由 Blink 生成,都需要產(chǎn)生一個(gè)新的 Main Frame;

合成器動(dòng)畫又可以分為兩類:

合成器本身觸發(fā)并運(yùn)行的,比如最常見的網(wǎng)頁慣性滾動(dòng),包括整個(gè)網(wǎng)頁或者某個(gè)頁內(nèi)可滾動(dòng)元素的滾動(dòng);
Blink 觸發(fā)然后交由合成器運(yùn)行,比如說傳統(tǒng)的 CSS Translation 或者新的 Animation API,如果它們觸發(fā)的動(dòng)畫經(jīng)由 Blink 判斷可以交由合成器運(yùn)行;

Blink 觸發(fā)的動(dòng)畫,如果是 Transform 和 Opacity 屬性的動(dòng)畫基本上都可以由合成器運(yùn)行,因?yàn)樗鼈儧]有改變圖層的內(nèi)容。不過即使可以交由合成器運(yùn)行,它們也需要產(chǎn)生一個(gè)新的 Main Frame 提交給合成器來觸發(fā)這個(gè)動(dòng)畫,如果這個(gè) Main Frame 包含了大量的圖層變更,也會(huì)導(dǎo)致觸發(fā)的瞬間卡頓,頁端事先對(duì)圖層結(jié)構(gòu)進(jìn)行優(yōu)化可以避免這個(gè)問題。

非合成器動(dòng)畫也可以分為兩類:

使用 CSS Translation 或者 Animation API 創(chuàng)建的動(dòng)畫,但是無法由合成器運(yùn)行;
使用 Timer 或者 rAF 由 JS 驅(qū)動(dòng)的動(dòng)畫,比較典型的就是 Canvas/WebGL 游戲,這種動(dòng)畫實(shí)際上是由頁端自己定義的,瀏覽器本身并沒有對(duì)應(yīng)的動(dòng)畫的概念,也就是說瀏覽器本身是不知道這個(gè)動(dòng)畫什么時(shí)候開始,是否正在運(yùn)行,什么時(shí)候結(jié)束,這些完全是頁端自己的內(nèi)部邏輯;

合成器動(dòng)畫和非合成器動(dòng)畫在渲染流水線上有較大的差異,后者更復(fù)雜,流水線更長(zhǎng)。上面四種動(dòng)畫的分類,按渲染流水線的復(fù)雜程度和理論性能排列(復(fù)雜程度由低到高,理論性能由高到低):

合成器本身觸發(fā)并運(yùn)行的動(dòng)畫;
Blink 觸發(fā),合成器運(yùn)行的動(dòng)畫;
Blink 觸發(fā),無法由合成器運(yùn)行的動(dòng)畫;
由 Timer/rAF 驅(qū)動(dòng)的 JS 動(dòng)畫;

開啟硬件加速的方法很多,比如transform:?translate3d(0,0,0); 加了之后,在chrome開發(fā)者工具中的layer欄目下可以看到多了一層 composition layer,同時(shí)給出了理由描述是開啟了3D transform,這個(gè)元素就放入了Composited Layer中托管,其動(dòng)畫效果都是在多帶帶一個(gè)圖形層上面處理,不會(huì)影響其它層。

什么情況下能使元素獲得自己的層?雖然 Chrome 的啟發(fā)式方法(heuristic)隨著時(shí)間在不斷發(fā)展進(jìn)步,但是從目前來說,滿足以下任意情況便會(huì)創(chuàng)建層:

3D 或透視變換(perspective transform) CSS 屬性
使用加速視頻解碼的 元素
擁有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
混合插件(如 Flash)
對(duì)自己的 opacity 做 CSS 動(dòng)畫或使用一個(gè)動(dòng)畫 webkit 變換的元素
擁有加速 CSS 過濾器的元素
元素有一個(gè)包含復(fù)合層的后代節(jié)點(diǎn)(換句話說,就是一個(gè)元素?fù)碛幸粋€(gè)子元素,該子元素在自己的層里)
元素有一個(gè) z-index 較低且包含一個(gè)復(fù)合層的兄弟元素(換句話說就是該元素在復(fù)合層上面渲染)

使用3D硬件加速提升動(dòng)畫性能時(shí),最好給元素增加一個(gè)z-index屬性,人為干擾復(fù)合層的排序,可以有效減少chrome創(chuàng)建不必要的復(fù)合層,提升渲染性能,移動(dòng)端優(yōu)化效果尤為明顯。

關(guān)于層的介紹:gpu-accelerated-compositing-in-chrome

理解CSS animations 和 transitions的性能問題與動(dòng)畫調(diào)試

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

13.你了解js的數(shù)據(jù)結(jié)構(gòu)嗎?基本數(shù)據(jù)類型有哪些?復(fù)雜數(shù)據(jù)類型有哪些?在內(nèi)存是如何表現(xiàn)的?

參考MDN,最新的 ECMAScript 標(biāo)準(zhǔn)定義了 7 種數(shù)據(jù)類型:

6 種原始類型:
Boolean
Null
Undefined
Number
String
Symbol?(ECMAScript 6 新定義)
和?Object

除 Object 以外的所有類型都是不可變的(值本身無法被改變)。例如,與 C 語言不同,JavaScript 中字符串是不可變的。JavaScript 中對(duì)字符串的操作一定返回了一個(gè)新字符串,原始字符串并沒有被改變。

標(biāo)準(zhǔn)的" 對(duì)象, 和函數(shù)【復(fù)雜數(shù)據(jù)類型】

日期:內(nèi)建的?Date?對(duì)象

數(shù)組和類型數(shù)組:

數(shù)組是一種使用整數(shù)作為鍵(integer-key-ed)屬性和長(zhǎng)度(length)屬性之間關(guān)聯(lián)的常規(guī)對(duì)象。此外,數(shù)組對(duì)象還繼承了 Array.prototype 的一些操作數(shù)組的便捷方法。例如,?indexOf?(搜索數(shù)組中的一個(gè)值) or?push?(向數(shù)組中添加一個(gè)元素),等等。?這使得數(shù)組是表示列表或集合的最優(yōu)選擇。

類型數(shù)組(Typed Arrays)是ECMAScript Edition 6中新定義的 JavaScript 內(nèi)建對(duì)象,提供了一個(gè)基本的二進(jìn)制數(shù)據(jù)緩沖區(qū)的類數(shù)組視圖。

集合對(duì)象Map、WeakMap、Set、WeakSet:這些數(shù)據(jù)結(jié)構(gòu)把對(duì)象的引用當(dāng)作鍵,其在ECMAScript第6版中有介紹。當(dāng)?Map?和?WeakMap?把一個(gè)值和對(duì)象關(guān)聯(lián)起來的時(shí)候,?Set?和?WeakSet?表示一組對(duì)象。 Map和WeakMaps之間的差別在于,在前者中,對(duì)象鍵是可枚舉的。

結(jié)構(gòu)化數(shù)據(jù)JSON:JSON (JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式

參考:標(biāo)準(zhǔn)全局內(nèi)置對(duì)象

兩種類型:

1.???ECMAScript變量包含兩種不同類型的值:基本類型值、引用類型值;

2.???基本類型值:指的是保存在棧內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段;

3.???引用類型值:指的是那些保存在堆內(nèi)存中的對(duì)象,意思是,變量中保存的實(shí)際上只是一個(gè)指針,這個(gè)指針執(zhí)行內(nèi)存中的另一個(gè)位置,由該位置保存對(duì)象;

兩種訪問方式:

4.???基本類型值:按值訪問,操作的是他們實(shí)際保存的值;

5.???引用類型值:按引用訪問,當(dāng)查詢時(shí),我們需要先從棧中讀取內(nèi)存地址,然后再順藤摸瓜地找到保存在堆內(nèi)存中的值;

數(shù)據(jù)復(fù)制

基本類型變量的復(fù)制:從一個(gè)變量向一個(gè)變量復(fù)制時(shí),會(huì)在棧中創(chuàng)建一個(gè)新值,然后把值復(fù)制到為新變量分配的位置上;
引用類型變量的復(fù)制:復(fù)制的是存儲(chǔ)在棧中的指針,將指針復(fù)制到棧中未新變量分配的空間中,而這個(gè)指針副本和原指針執(zhí)行存儲(chǔ)在堆中的同一個(gè)對(duì)象;復(fù)制操作結(jié)束后,兩個(gè)變量實(shí)際上將引用同一個(gè)對(duì)象;因此改變其中的一個(gè),將影響另一個(gè);

三種變量類型檢測(cè)

1.???Typeof操作符是檢測(cè)基本類型的最佳工具;

2.???如果變量值是null或者對(duì)象,typeof?將返回“object”;結(jié)合null == null 來判斷

3.???Instanceof用于檢測(cè)引用類型,可以檢測(cè)到具體的,它是什么類型的實(shí)例;

4.???如果變量是給定引用類型的實(shí)例,instanceof操作符會(huì)返回true;

Object.prototype.toString.call(xx) 來打印原型判斷類型

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

14.你可以用js去實(shí)現(xiàn)一個(gè)單向、雙向、循環(huán)鏈表嗎?你可以實(shí)現(xiàn)查找、插入、刪除操作嗎?

可以在這里試一下:在線編程環(huán)境

鏈表:

插入鏈表節(jié)點(diǎn):

刪除鏈表節(jié)點(diǎn):

雙向鏈表:

循環(huán)鏈表:

下面給一個(gè)最簡(jiǎn)單的單項(xiàng)鏈表示例:

/**
** 先創(chuàng)建一個(gè)節(jié)點(diǎn)類,記錄當(dāng)前數(shù)據(jù),和下個(gè)節(jié)點(diǎn),如果是雙向鏈表,就包含prev
** prev: 對(duì)上個(gè)節(jié)點(diǎn)的引用
** next: 對(duì)下個(gè)節(jié)點(diǎn)的應(yīng)用
**/
class Node{
  constructor(data){
    this.data = data;
    this.next = null;
  }
}
/**
** 創(chuàng)建鏈表,head是鏈表中的一個(gè)起始節(jié)點(diǎn),關(guān)于單項(xiàng)鏈表,雙向鏈表和循環(huán)鏈表參考文章介紹
** find: 找到數(shù)據(jù)所在的節(jié)點(diǎn),這里是示例,其實(shí)應(yīng)該有個(gè)唯一標(biāo)識(shí)
** insert: 在指定節(jié)點(diǎn)后面插入節(jié)點(diǎn)
**/
class LinkTable{
  constructor(data){
    this.head = null;
    this.end = null;
    if(data){
      this.head = new Node(data)
    }
  }
  find(data){
    let start = this.head;
    while(start.data != data){
      start = start.next;
    }
    return start;
  }
  insert(data,node){
    let nod = new Node(data);
    nod.next = node.next;
    item.next = nod;
  }
}

關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端

14.你了解基本常見算法嗎?快速排序?qū)懸粋€(gè)?要是限制空間利用你該如何寫?

快速排序:

(1)在數(shù)據(jù)集之中,選擇一個(gè)元素作為"基準(zhǔn)"(pivot)。

(2)所有小于"基準(zhǔn)"的元素,都移到"基準(zhǔn)"的左邊;所有大于"基準(zhǔn)"的元素,都移到"基準(zhǔn)"的右邊。

(3)對(duì)"基準(zhǔn)"左邊和右邊的兩個(gè)子集,不斷重復(fù)第一步和第二步,直到所有子集只剩下一個(gè)元素為止。

選擇排序:

(1)首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

(2)再?gòu)氖S辔磁判蛟刂欣^續(xù)尋找最?。ù螅┰兀缓蠓诺揭雅判蛐蛄械哪┪?/p>

(3)直到所有都排序

冒泡排序:

比較相鄰的元素。如果第一個(gè)比第二個(gè)大,就交換他們兩個(gè)。
對(duì)每一對(duì)相鄰元素作同樣的工作,從開始第一對(duì)到結(jié)尾的最后一對(duì)。在這一點(diǎn),最后的元素應(yīng)該會(huì)是最大的數(shù)。
針對(duì)所有的元素重復(fù)以上的步驟,除了最后一個(gè)。
持續(xù)每次對(duì)越來越少的元素重復(fù)上面的步驟,直到?jīng)]有任何一對(duì)數(shù)字需要比較。

直接插入排序:

(1)將待排序數(shù)組取一個(gè)數(shù)值插入到已排序數(shù)組中合適的位置

(2)重復(fù)取數(shù)據(jù),直到所有數(shù)據(jù)取完

15.你了解貪心算法、動(dòng)態(tài)規(guī)劃、分治算法、回溯算法等常見的算法嗎?

貪心算法

?所謂貪心算法是指,在對(duì)問題求解時(shí),總是做出在當(dāng)前看來是最好的選擇。也就是說,不從整體最優(yōu)上加以考慮,他所做出的僅是在某種意義上的局部最優(yōu)解。
?????貪心算法沒有固定的算法框架,算法設(shè)計(jì)的關(guān)鍵是貪心策略的選擇。必須注意的是,貪心算法不是對(duì)所有問題都能得到整體最優(yōu)解,選擇的貪心策略必須具備無后效性,即某個(gè)狀態(tài)以后的過程不會(huì)影響以前的狀態(tài),只與當(dāng)前狀態(tài)有關(guān)。
????所以對(duì)所采用的貪心策略一定要仔細(xì)分析其是否滿足無后效性。
貪心算法的基本思路:
??? 1.建立數(shù)學(xué)模型來描述問題。
??? 2.把求解的問題分成若干個(gè)子問題。
??? 3.對(duì)每一子問題求解,得到子問題的局部最優(yōu)解。
??? 4.把子問題的解局部最優(yōu)解合成原來解問題的一個(gè)解。

動(dòng)態(tài)規(guī)劃算法

動(dòng)態(tài)規(guī)劃過程是:每次決策依賴于當(dāng)前狀態(tài),又隨即引起狀態(tài)的轉(zhuǎn)移。一個(gè)決策序列就是在變化的狀態(tài)中產(chǎn)生出來的,所以,這種多階段最優(yōu)化決策解決問題的過程就稱為動(dòng)態(tài)規(guī)劃。

?? ?基本思想與分治法類似,也是將待求解的問題分解為若干個(gè)子問題(階段),按順序求解子階段,前一子問題的解,為后一子問題的求解提供了有用的信息。在求解任一子問題時(shí),列出各種可能的局部解,通過決策保留那些有可能達(dá)到最優(yōu)的局部解,丟棄其他局部解。依次解決各子問題,最后一個(gè)子問題就是初始問題的解。

?? ?由于動(dòng)態(tài)規(guī)劃解決的問題多數(shù)有重疊子問題這個(gè)特點(diǎn),為減少重復(fù)計(jì)算,對(duì)每一個(gè)子問題只解一次,將其不同階段的不同狀態(tài)保存在一個(gè)二維數(shù)組中。

?? ?與分治法最大的差別是:適合于用動(dòng)態(tài)規(guī)劃法求解的問題,經(jīng)分解后得到的子問題往往不是互相獨(dú)立的(即下一個(gè)子階段的求解是建立在上一個(gè)子階段的解的基礎(chǔ)上,進(jìn)行進(jìn)一步的求解)。

能采用動(dòng)態(tài)規(guī)劃求解的問題的一般要具有3個(gè)性質(zhì):

??? (1) 最優(yōu)化原理:如果問題的最優(yōu)解所包含的子問題的解也是最優(yōu)的,就稱該問題具有最優(yōu)子結(jié)構(gòu),即滿足最優(yōu)化原理。

??? (2) 無后效性:即某階段狀態(tài)一旦確定,就不受這個(gè)狀態(tài)以后決策的影響。也就是說,某狀態(tài)以后的過程不會(huì)影響以前的狀態(tài),只與當(dāng)前狀態(tài)有關(guān)。

?? (3)有重疊子問題:即子問題之間是不獨(dú)立的,一個(gè)子問題在下一階段決策中可能被多次使用到。(該性質(zhì)并不是動(dòng)態(tài)規(guī)劃適用的必要條件,但是如果沒有這條性質(zhì),動(dòng)態(tài)規(guī)劃算法同其他算法相比就不具備優(yōu)勢(shì))

分治算法

分治法的設(shè)計(jì)思想是:將一個(gè)難以直接解決的大問題,分割成一些規(guī)模較小的相同問題,以便各個(gè)擊破,分而治之。

分治策略是:對(duì)于一個(gè)規(guī)模為n的問題,若該問題可以容易地解決(比如說規(guī)模n較?。﹦t直接解決,否則將其分解為k個(gè)規(guī)模較小的子問題,這些子問題互相獨(dú)立且與原問題形式相同,遞歸地解這些子問題,然后將各子問題的解合并得到原問題的解。這種算法設(shè)計(jì)策略叫做分治法。

分治法所能解決的問題一般具有以下幾個(gè)特征:

1) 該問題的規(guī)模縮小到一定的程度就可以容易地解決

2) 該問題可以分解為若干個(gè)規(guī)模較小的相同問題,即該問題具有最優(yōu)子結(jié)構(gòu)性質(zhì)。

3) 利用該問題分解出的子問題的解可以合并為該問題的解;

4) 該問題所分解出的各個(gè)子問題是相互獨(dú)立的,即子問題之間不包含公共的子子問題。

回溯法

在包含問題的所有解的解空間樹中,按照深度優(yōu)先搜索的策略,從根結(jié)點(diǎn)出發(fā)深度探索解空間樹。當(dāng)探索到某一結(jié)點(diǎn)時(shí),要先判斷該結(jié)點(diǎn)是否包含問題的解,如果包含,就從該結(jié)點(diǎn)出發(fā)繼續(xù)探索下去,如果該結(jié)點(diǎn)不包含問題的解,則逐層向其祖先結(jié)點(diǎn)回溯。(其實(shí)回溯法就是對(duì)隱式圖的深度優(yōu)先搜索算法)

分支限界法

類似于回溯法,也是一種在問題的解空間樹T上搜索問題解的算法。但在一般情況下,分支限界法與回溯法的求解目標(biāo)不同?;厮莘ǖ那蠼饽繕?biāo)是找出T中滿足約束條件的所有解,而分支限界法的求解目標(biāo)則是找出滿足約束條件的一個(gè)解,或是在滿足約束條件的解中找出使某一目標(biāo)函數(shù)值達(dá)到極大或極小的解,即在某種意義下的最優(yōu)解。

由于求解目標(biāo)不同,導(dǎo)致分支限界法與回溯法在解空間樹T上的搜索方式也不相同。回溯法以深度優(yōu)先的方式搜索解空間樹T,而分支限界法則以廣度優(yōu)先或以最小耗費(fèi)優(yōu)先的方式搜索解空間樹T。

16.你是如何理解前端架構(gòu)的?你了解持續(xù)集成嗎?

架構(gòu),我理解主要做:系統(tǒng)分解、服務(wù)分層的工作。

持續(xù)集成?(Continuous integration,簡(jiǎn)稱CI)。項(xiàng)目是一個(gè)迭代一個(gè)迭代快速開發(fā),每個(gè)迭代開發(fā)不同的feature,所有的feature合在一起構(gòu)成完整的功能。

持續(xù)集成的目的,就是讓產(chǎn)品可以快速迭代,同時(shí)還能保持高質(zhì)量。它的核心措施是,代碼集成到主干之前,必須通過自動(dòng)化測(cè)試。只要有一個(gè)測(cè)試用例失敗,就不能集成。

Martin Fowler說過,"持續(xù)集成并不能消除Bug,而是讓它們非常容易發(fā)現(xiàn)和改正。"

與持續(xù)集成相關(guān)的,還有兩個(gè)概念,分別是持續(xù)交付和持續(xù)部署。

17.你了解基本的設(shè)計(jì)模式嗎?舉例單例模式、策略模式、代理模式、迭代模式、發(fā)布訂閱模式。。。?

設(shè)計(jì)模式(Design pattern)代表了最佳的實(shí)踐,通常被有經(jīng)驗(yàn)的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計(jì)模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。

單例模式:

單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。

這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建。這個(gè)類提供了一種訪問其唯一的對(duì)象的方式,可以直接訪問,不需要實(shí)例化該類的對(duì)象。

注意:

1、單例類只能有一個(gè)實(shí)例。
2、單例類必須自己創(chuàng)建自己的唯一實(shí)例。
3、單例類必須給所有其他對(duì)象提供這一實(shí)例。

策略模式

在策略模式(Strategy Pattern)中,一個(gè)類的行為或其算法可以在運(yùn)行時(shí)更改。這種類型的設(shè)計(jì)模式屬于行為型模式。

在策略模式中,我們創(chuàng)建表示各種策略的對(duì)象和一個(gè)行為隨著策略對(duì)象改變而改變的 context 對(duì)象。策略對(duì)象改變 context 對(duì)象的執(zhí)行算法。

很好理解,比如上面給的一個(gè)異常處理的代碼,寫個(gè)簡(jiǎn)單的示例。

export class RuntimeException {

    constructor(message) {
        this._message = message;
    }

    get name() {
        return "RuntimeException";
    }

    get message() {
        return this._message;
    }

    toString() {
        return this.name + ": " + this.message;
    }

}

export class IllegalStateException extends RuntimeException {

    constructor(message) {
        super(message);
    }

    get name() {
        return "IllegalStateException";
    }

}

export class InvalidArgumentException extends RuntimeException {

    constructor(message) {
        super(message);
    }

    get name() {
        return "InvalidArgumentException";
    }

}

export class NotImplementedException extends RuntimeException {

    constructor(message) {
        super(message);
    }

    get name() {
        return "NotImplementedException";
    }

}

export function funcWrapper(args){
    try{
      if(!args) throw new InvalidArgumentException("args undefined")
      if(args == 1) throw new IllegalStateException("args illegal")
    }catch(e){
        console.log(e.toString())
    }
}

瀏覽器可以跑下結(jié)果看看:

這就是策略模式,不同的情況,輸出的結(jié)果是不一樣的。

18.寫一個(gè)事件監(jiān)聽函數(shù)唄?實(shí)現(xiàn)once、on、remove、emit功能

19.node.js的實(shí)現(xiàn)層是什么?

20.node的事件循環(huán)機(jī)制是怎樣的?node的child_process模塊有幾個(gè)api,分別的作用是什么?

22.http1.0與1.1協(xié)議的區(qū)別?node是如何實(shí)現(xiàn)http模塊的?

25.nginx相關(guān)配置了解過嗎?

27.小程序架構(gòu)

28.vue v-model 語法糖?vue push式更新?vue computed和watch的區(qū)別?

29.redux dispatch一個(gè)action之后的更新過程
connect的時(shí)候出于性能優(yōu)化的考慮做了一層淺比較。

30.假設(shè)頁面有多個(gè)模塊,每個(gè)模塊都用到了getUser方法獲取用戶信息,怎么設(shè)計(jì)通用的getUser避免發(fā)出多次請(qǐng)求。
這個(gè)是一個(gè)朋友給的網(wǎng)易考拉前端的面試題,朋友給了2個(gè)解法:

監(jiān)聽者模式,監(jiān)聽getUser事件,第一次注冊(cè)監(jiān)聽事件時(shí)發(fā)出請(qǐng)求,待請(qǐng)求數(shù)據(jù)回來,執(zhí)行所有回調(diào)。通過事件監(jiān)聽解耦。

基于promise,getUser方法提供一個(gè)thenable的能力,返回一個(gè)promise對(duì)象,在Promise中將resolve維護(hù)在一個(gè)resolveList列表中,其實(shí)和事件監(jiān)聽中的事件列表類似。第一次調(diào)用時(shí)發(fā)出請(qǐng)求,請(qǐng)求回來后調(diào)用resolveList列表中所有resolve。

個(gè)人感覺基于promise的方法比事件監(jiān)聽模式更優(yōu),本來就是一步的操作返回的也是一個(gè)Promise,更符合編碼邏輯。

說到最后,結(jié)合朋友的面試分享一下:
朋友說網(wǎng)易考拉前端的面試官姿態(tài)比較高,一種專橫跋扈的感覺,沒有耐心,固步自封,整體面試體驗(yàn)比較差,而且面試官都是比較自以為是那種。朋友說有個(gè)面試官明顯沒準(zhǔn)備,邊問邊看簡(jiǎn)歷,沒有重點(diǎn)和主線,然后讓他提問2個(gè)面試官不知道的問題,結(jié)果他誰便說了2個(gè),面試官真的不知道,場(chǎng)面很尷尬。而且有幾個(gè)面試官在面試中還說錯(cuò)了一些技術(shù)知識(shí)點(diǎn)。整體感覺面試官問的問題都是比較分散,很隨意,也反映出網(wǎng)易考拉前端的技術(shù)基礎(chǔ)建設(shè)也是比較差勁的,技術(shù)主管只關(guān)注業(yè)務(wù)實(shí)現(xiàn),對(duì)于技術(shù)體系建設(shè),技術(shù)規(guī)劃設(shè)計(jì)都沒有概念,這種團(tuán)隊(duì)的技術(shù)氛圍可想而知。最后朋友說他問了那個(gè)技術(shù)主管對(duì)于技術(shù)體系建設(shè)和規(guī)劃是什么?怎么支撐業(yè)務(wù)發(fā)展?結(jié)果也沒說什么。
其實(shí)可以考慮阿里、騰訊這種大公司,面試體驗(yàn)絕對(duì)不一樣,技術(shù)體系建設(shè),知識(shí)面廣度和深度,不是在一個(gè)檔次的。能去大廠還是考慮大廠,畢竟大廠是有真正的大牛在。

本文總結(jié)了前端老司機(jī)經(jīng)常問題的一些問題并結(jié)合個(gè)人總結(jié)給出了比較詳盡的答案。
關(guān)于知識(shí)點(diǎn)原理和詳細(xì),參考講堂的視頻教程:前端增長(zhǎng)-重新定義大前端
課程知識(shí)在不斷更新,本片內(nèi)容也逐步更新

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105658.html

相關(guān)文章

  • 校招社招必備核心前端面試問題詳細(xì)解答

    摘要:本文總結(jié)了前端老司機(jī)經(jīng)常問題的一些問題并結(jié)合個(gè)人總結(jié)給出了比較詳盡的答案。網(wǎng)易阿里騰訊校招社招必備知識(shí)點(diǎn)。此外還有網(wǎng)絡(luò)線程,定時(shí)器任務(wù)線程,文件系統(tǒng)處理線程等等。線程核心是引擎。主線程和工作線程之間的通知機(jī)制叫做事件循環(huán)。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文總結(jié)了前端老司機(jī)經(jīng)常問題的一些問題并結(jié)合個(gè)...

    Rango 評(píng)論0 收藏0
  • 校招社招必備核心前端面試問題詳細(xì)解答

    摘要:本文總結(jié)了前端老司機(jī)經(jīng)常問題的一些問題并結(jié)合個(gè)人總結(jié)給出了比較詳盡的答案。網(wǎng)易阿里騰訊校招社招必備知識(shí)點(diǎn)。此外還有網(wǎng)絡(luò)線程,定時(shí)器任務(wù)線程,文件系統(tǒng)處理線程等等。線程核心是引擎。主線程和工作線程之間的通知機(jī)制叫做事件循環(huán)。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文總結(jié)了前端老司機(jī)經(jīng)常問題的一些問題并結(jié)合個(gè)...

    DevTalking 評(píng)論0 收藏0
  • 前端工程師手冊(cè)】JavaScript之閉包

    摘要:閉包確實(shí)是一個(gè)說爛了的概念,校招社招都會(huì)被問到,今天總結(jié)一番。先下定義,閉包是函數(shù)和該函數(shù)的詞法作用域的組合。在這個(gè)栗子里,函數(shù)以及它對(duì)變量的引用就構(gòu)成了閉包。閉包和作用域?qū)τ陂]包和作用域的關(guān)系,我的理解是閉包其實(shí)就是作用域的延伸。 閉包確實(shí)是一個(gè)說爛了的概念,校招社招都會(huì)被問到,今天總結(jié)一番。先下定義,閉包是函數(shù)和該函數(shù)的詞法作用域的組合。其實(shí)這個(gè)定義是比較教條的,可以直白的理解為閉...

    CarlBenjamin 評(píng)論0 收藏0
  • "雙非"應(yīng)屆生校招如何獲得大廠青睞?(內(nèi)附前端大廠面經(jīng)+技術(shù)崗超全求職攻略)

    摘要:拿到秋招的同學(xué),如確定入職需與用人單位簽署三方協(xié)議,以保證雙方的利益不受損失。當(dāng)然每個(gè)崗位所要求的側(cè)重點(diǎn)不同,但卻百變不離其宗。方法論要想達(dá)成某個(gè)目標(biāo)都有其特定的方法論,學(xué)習(xí)技術(shù)也不例外,掌握適當(dāng)?shù)膶W(xué)習(xí)方法才能事半功倍。 寫在前面的話 筆者從17年的2月份開始準(zhǔn)備春招,其中遇到不少坑,也意識(shí)到自己走過的彎路。故寫了這篇文章總結(jié)一番,本文適合主動(dòng)學(xué)習(xí)的,對(duì)自己要學(xué)的課程不明確的,對(duì)面試有...

    jeffrey_up 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<