筆者雖然曾經也面試過很多求職者,但是對於前端的筆試和麵試,我覺得並不能體現一個人的真實能力,所以建議大家多修煉前端真正的技術.對於前端面試題,之前也承諾過讀者要出一篇,筆者大致總結一下曾今面試的題目.後續不會再出面試題,而是聚焦於一些真正的,有利於成長性的技術文章和思維方式,來幫助大家提高解決問題的能力.
前言
首先總結一下筆者對於前端領域學習的一些成長模型和學習路線,來給大家提供一些參考.
下面推薦一些不同技術選型的優秀元件和庫,也是筆者曾今使用過的.如果公司的前端是以vue為主的,那麼你可能需要熟悉如下技能和知識點
- vue
- vue-router 路由管理
- vuex 狀態管理
- vue-cli3 vue專案優秀的腳手架,可以配置單頁,多頁,ssr, 預渲染技術的頁面
- vue-server-renderer 服務端渲染方案
- vue-devtools vue開發除錯工具,方便除錯大型複雜專案
- antd-desigin-vue / element UI 基於vue的第三方ui元件庫
- vxe-table 優秀的vue表格解決方案
- vue-multiselect vue強大的多選下拉元件
- Vuelidate 基於vue強大且輕量的校驗庫
- vuex-router-sync 保持vue-router和vuex store同步
如果公司的前端是以React為主的,那麼你可能需要熟悉如下技能和知識點
- react
- react-router
- react-thunk 非同步redux解決方案
- ant design 優秀且強大的react元件庫
- react-json-view JSON 顯示器
- react-quill 富文字編輯器
- rc-color-picker 拾色器
- qrcode.react 二維碼生成器
- antV 資料視覺化解決方案
- react-beautiful-dnd 基於react的拖拽庫
- emoji-mart 表情庫
- react-image-crop 圖片裁切
- Ant Motion 動畫
- react-codemirror2 程式碼編輯器
- react-copy-to-clipboard 複製到剪下板
接下來言歸正傳,開始進入正文.
正文
1. 介紹一下ES6的新特性
[參考答案]
- const和let
- 模板字串
- 箭頭函式
- 函式的引數預設值
- Spread / Rest 操作符
- 二進位制和八進位制字面量(通過在數字前面新增0o或0O即可將其轉為八進位制值,二進位制使用
0b
或者0B
) - 物件和陣列解構
- ES6中的類(class)
- Promise
- Set()和Map()資料結構
- Modules(模組, 如import, export)
- for..of 迴圈
2. 介紹Promise以及Promise的幾種狀態
[參考答案]
介紹: Promise 是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函式和事件——更合理和更強大。所謂Promise,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說,Promise 是一個物件,從它可以獲取非同步操作的訊息。Promise 提供統一的 API,各種非同步操作都可以用同樣的方法進行處理。 狀態: pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
3. 談談你對閉包的理解及其優缺點
[參考答案]
閉包就是能夠讀取其他函式內部變數的函式. 本質上,閉包是將函式內部和函式外部連線起來的橋樑.
優點
- 邏輯連續,當閉包作為另一個函式呼叫引數時,避免脫離當前邏輯而單獨編寫額外邏輯。
- 延長區域性變數的生命週期, 更具有封裝性, 保護區域性變數。
缺點
- 容易造成記憶體溢位
- 閉包會在父函式外部,改變父函式內部變數的值,所以可能會導致改變父函式的變數
4. React的生命週期
[參考答案]
- 初始化階段 defaultProps -> constructor -> componentWillMount() -> render() -> componentDidMount()
- 執行中階段 componentWillReceiveProps() -> shouldComponentUpdate() -> componentWillUpdate() -> componentDidUpdate()
- 銷燬階段 componentWillUnmount()
5. componentWillReceiveProps的觸發條件是什麼
[參考答案] componentWillReceiveProps會在接收到新的props的時候呼叫
6. vue中v-if和v-show的區別
[參考答案]
- v-show不管條件是真還是假,第一次渲染的時候標籤都會新增到DOM中。切換的時候,通過display: none;樣式來顯示隱藏元素,對效能影響不是很大。
- v-if在首次渲染的時候,如果條件為假,不會在頁面渲染該元素。當條件為真時,開始區域性編譯,動態的向DOM元素裡面新增元素。當條件從真變為假的時候,開始區域性編譯,解除安裝這些元素,也就是刪除。對效能有一定影響
7. 小程式裡面開頁面最多多少
[參考答案] 小程式原生頁面存在層級限制,超過一定層數就會無法開啟新頁面。一開始這個限制為不超過5層,目前是不超過10層。
8. 取陣列的最大值(ES5、ES6)
[參考答案]
// es5
Math.max.apply(null, arr);
// es6
Math.max(...arr);
複製程式碼
9. http併發請求資源數上限
[參考答案] HTTP客戶端一般對同一個伺服器的併發連線個數都是有限制的, 最大為6條
10. 如何優化網站的SEO
[參考答案]
- 網站結構佈局優化:儘量簡單, 提倡扁平化結構. 一般而言,建立的網站結構層次越少,越容易被“蜘蛛”抓取,也就容易被收錄。
- img標籤必須新增“alt”和“title”屬性,告訴搜尋引擎導航的定位,做到即使圖片未能正常顯示時,使用者也能看到提示文字。
- 把重要內容HTML程式碼放在最前搜尋引擎抓取HTML內容是從上到下,利用這一特點,可以讓主要程式碼優先讀取,廣告等不重要程式碼放在下邊。
- 控制頁面的大小,減少http請求,提高網站的載入速度。
- 合理的設計title、description和keywords
- title標題:只強調重點即可,儘量把重要的關鍵詞放在前面,關鍵詞不要重複出現,儘量做到每個頁面的title標題中不要設定相同的內容。
- meta keywords頁面/網站的關鍵字。
- meta description網頁描述,需要高度概括網頁內容,切記不能太長,過分堆砌關鍵詞,每個頁面也要有所不同。
- 語義化書寫HTML程式碼,符合W3C標準儘量讓程式碼語義化,在適當的位置使用適當的標籤,用正確的標籤做正確的事。讓閱讀原始碼者和“蜘蛛”都一目瞭然。
- a標籤:頁面連結,要加 “title” 屬性說明,連結到其他網站則需要加上 el="nofollow" 屬性, 告訴 “蜘蛛” 不要爬,因為一旦“蜘蛛”爬了外部連結之後,就不會再回來了。
- 圖示使用IconFont替換
- 使用CDN網路快取,加快使用者訪問速度,減輕伺服器壓力
- 啟用GZIP壓縮,瀏覽速度變快,搜尋引擎的蜘蛛抓取資訊量也會增大
- SSR技術
- 預渲染技術
11. 介紹下HTTP狀態碼, 403、301、302分別代表什麼
[參考答案]
當瀏覽者訪問一個網頁時,瀏覽者的瀏覽器會向網頁所在伺服器發出請求。當瀏覽器接收並顯示網頁前,此網頁所在的伺服器會返回一個包含HTTP狀態碼的資訊頭(server header)用以響應瀏覽器的請求。
- 301 (永久移動) 請求的網頁已永久移動到新位置。 伺服器返回此響應(對 GET 或 HEAD 請求的響應)時,會自動將請求者轉到新位置
- 302 (臨時移動) 伺服器目前從不同位置的網頁響應請求,但請求者應繼續使用原有位置來進行以後的請求
- 403 (禁止) 伺服器拒絕請求
12. RESTful常用的方法和介紹
[參考答案] rest請求方法有4種,包括get,post,put,delete.分別對應獲取資源,新增資源,更新資源及刪除資源.
12. React16.3對生命週期的改變
[參考答案] React16.3+廢棄的三個生命週期函式
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
取而代之的是兩個新的生命週期函式
- static getDerivedStateFromProps(nextProps, prevState) 取代componentWillMount、componentWillReceiveProps和componentWillUpdate
- getSnapshotBeforeUpdate(prevProps, prevState) 取代componentWillUpdate
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 返回的資料將作為componentDidUpdate第三個引數
return {
stateA: 'xxx'
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (snapshot !== null) {
console.log(snapshot.stateA)
}
}
render() {}
}
複製程式碼
13. 介紹React高階元件
高階元件(HOC)是 React 中用於複用元件邏輯的一種高階技巧。HOC 自身不是 React API 的一部分,它是一種基於 React 的組合特性而形成的設計模式。具體而言,高階元件是引數為元件,返回值為新元件的函式.其本身是純函式,沒有副作用。
function logProps(WrappedComponent) {
return class extends React.Component {
componentWillReceiveProps(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
}
render() {
// 將 input 元件包裝在容器中,而不對其進行修改。Good!
return <WrappedComponent {...this.props} />;
}
}
}
複製程式碼
14. 快取相關的HTTP請求頭
[參考答案]
headers欄位 | 解釋 | 案例 |
---|---|---|
Expires | 服務端告訴瀏覽器,先把這個檔案快取起來,在這個過期時間之前,該檔案都不會變化 | Expires: Mon, 1 Aug 2016 22:43:02 GMT |
Cache-Control | 由於Expires給定的是絕對時間,而客戶端的系統時間可以由使用者任意修改, Cache-Control為相對時間 | Cache-Control: max-age=80 |
Last-Modified(response header) / If-Modified-Since (request header) | 服務端收到請求後會對比目前檔案的最後修改時間和該請求頭的資訊,如果沒有修改,那就直接返回304給瀏覽器,而不返回實際資源。如果有變化了,就返回200,並且帶上新的資源內容 | If-Modified-Since:Mon, 01 Aug 2016 13:48:44 GMT |
Etag / If-None-Match | 第一次請求後響應頭中包含了Etag,作為時間標籤,下一次請求時會把原來的Etag標籤帶上(在請求頭中變成了If-None-Match)作為校驗標準,若這個檔案如果發生了改變,則Etag也會改變。伺服器對比瀏覽器請求頭中的的If-None-Match:如果相同就返回304,而不返回實際資源如果不同,就返回200和新的資源。 |
15. 如何優化使用者體驗
[參考答案]
- 頁面渲染前使用骨架屏或者載入動畫,避免大塊白屏
- 使用預渲染或者ssr技術提高首屏載入時間
- 動畫使用css3硬體加速,避免使用者操作動畫卡頓
- 計算密集型業務使用web worker或者js分片處理,避免js執行緒阻塞
- 頁面狀態監控,給使用者提供反饋機制
- 靜態資源走CDN快取或者oss服務,提高使用者訪問速度
- 避免使用者操作報錯,提供404頁面或則錯誤提示頁面
16. 對PWA的瞭解
[參考答案]
progressive web app: 漸進式網頁應用.可以將 Web 和 App 各自的優勢融合在一起:漸進式、可響應、可離線、實現類似 App 的互動、即時更新、安全、可以被搜尋引擎檢索、可推送、可安裝、可連結。其核心技術包括 App Manifest、Service Worker、Web Push,等等。
17. 介紹下跨域
[參考答案]
同源策略/SOP(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊, 同源策略要求兩個通訊地址的協議、域名、埠號必須相同,否則兩個地址的通訊將被瀏覽器視為不安全的,並被阻擋下來. 要突破SOP的限制,我們可以使用如下方式:
- CORS 同域安全策略CORS是一種跨域資源請求機制,它要求當前域在響應報頭新增Access-Control-Allow-Origin標籤,從而允許指定域的站點訪問當前域上的資源
res.setHeader("Access-Control-Allow-Origin","*");
// 不過CORS預設只支援GET/POST這兩種http請求型別,如果要開啟PUT/DELETE之類的方式,需要在服務端在新增一個"Access-Control-Allow-Methods"報頭標籤:
res.setHeader(
"Access-Control-Allow-Methods",
"PUT, GET, POST, DELETE, HEAD, PATCH"
)
複製程式碼
-
HTML5 postMessage 可以使用 postMessage 方法和 onmessage 事件來實現不同域之間的通訊,其中postMessage用於實時向接收資訊的頁面傳送訊息
-
HTML5 WebSocket WebSocket protocol 是HTML5一種新的協議。它實現了瀏覽器與伺服器全雙工通訊,同時允許跨域通訊,是server push技術的一種很棒的實現
-
JSONP 是JSON的一種“使用模式”,主要是利用script標籤不受同源策略限制的特性,向跨域的伺服器請求並返回一段JSON資料
-
iframe形式 通過設定相同的document.domain, 或者不同域通過window.name傳遞資料
-
伺服器代理
18. Access-Control-Allow-Origin在服務端哪裡配置
[參考答案] response header響應頭
19. csrf跨站攻擊怎麼解決
[參考答案]
CSRF, 跨站請求偽造,它可以在使用者毫不知情的情況下以使用者名稱義偽造請求傳送給受攻擊站點,從而對使用者或者網站造成攻擊. 預防措施如下:
- 伺服器端驗證HTTP Referer欄位, Referer記錄了該HTTP請求的來源地址
- 在請求地址中新增token並驗證
- 在HTTP頭中自定義屬性並驗證
20. 用js寫一個陣列扁平化函式
[參考答案]
// reduce
function flatten(arr = []) {
return arr.reduce((result, item) => {
return result.concat(Array.isArray(item) ? flatten(item) : item)
}, [])
}
// (toString | join) & split(利用陣列的toString或者join,將陣列轉化為字串)
function flatten(arr = []) {
return arr.toString().split(',').map(item => Number(item))
}
複製程式碼
21. Promise和Callback有什麼區別
[參考答案]
相比於callback,Promise 具有更易讀的程式碼組織形式(鏈式結構呼叫),更好的異常處理方式(在呼叫 Promise 的末尾新增上一個catch方法捕獲異常即可),以及非同步操作並行處理的能力(Promise.all()Promise.race()等)。callback最大的問題就是我們通常說的回撥地獄,一旦業務邏輯複雜了,我們不得不使用大量的巢狀回撥程式碼,可維護性很低.
22. 如何實現高度自適應
[參考答案]
- 使用絕對定位, 設定top,bottom屬性
- 使用flex佈局
- float+ height:100%
23. cookie, session, storage的區別和聯絡
[參考答案]
- cookie儲存於瀏覽器端,而session儲存於服務端
- cookie的安全性相比於session較弱,cookie容易被第三方劫持,考慮到安全應當使用session
- session儲存在伺服器上,當訪問增多時,會佔用伺服器的資源
- cookie儲存容量有限制,單個cookie儲存資料不能超過4k,且很多瀏覽器限制一個站點最多儲存20個cookie。對於session,預設大小一般是1M
- cookie、sessionStorage、localStorage,都儲存在瀏覽器端,且受同源策略影響
- cookie資料始終在同源的http請求中攜帶,而Storage不會再請求中攜帶,僅在本地儲存
- 儲存大小上, cookie一般是4k,Storage可以達到5M-10M
- 資料儲存時間上:sessionStorage僅僅是會話級別的儲存,它只在當前瀏覽器關閉前有效,不能持久保持;localStorage始終有效,即使視窗或瀏覽器關閉也一直有效,除非使用者手動刪除;cookie只在設定的 過期時間之前有效
- 作用域上:sessionStorage不在不同的瀏覽器視窗中共享,即使是同一個頁面; localStorage和 cookie在所有同源視窗是共享的
- Storage支援事件通知機制,可以將資料更新的通知傳送給監聽者。並且它提供增刪查api使用更方便
24. 說說你做過的前端效能優化(JS原生,React, vue)
[參考答案] 參考<趣談前端>週二打卡答案
25. 對web安全的理解
[參考答案]
- CSRF 攻擊和防範
跨站請求偽造,可以理解為攻擊者盜用了使用者的身份,以使用者的名義傳送惡意請求,造成使用者隱私及財產損失 過程: 1.登入受信任網站並在本地生成cookie; 2.在不登出 網站 的情況下訪問危險網站 防範: 關鍵操作只接受POST請求, 使用驗證碼, 檢測Referer, 使用token(或者JWT)
- XSS 攻擊和防範
全稱Cross-site script,跨站指令碼攻擊,是Web程式中常見的漏洞。原理是攻擊者向有XSS漏洞的網站中輸入惡意的指令碼,當其它使用者瀏覽該網站時候,該指令碼會自動執行,從而達到攻擊的目的(盜取Cookie,破壞頁面結構,重定向到釣魚網站等)。 區分: 分為持久型XSS和非永續性XSS. 持久型XSS是將攻擊的指令碼植入到伺服器,從而導致每個訪問的使用者都會遭到此XSS指令碼的攻擊。非持久型XSS是將惡意指令碼包裝在頁面的URL引數中,通過URL連結騙取使用者訪問,從而進行攻擊. 防範: 對使用者輸入進行HTML轉義, 對敏感資訊進行過濾
- SQL 注入與防範
通過把SQL命令插入到表單中並提交或頁面請求的引數中,最終使得伺服器執行惡意的SQL命令. 防範: 對使用者的輸入進行校驗或限制長度;對特殊字元進行轉換, 不要使用動態拼裝SQL,為每個應用使用單獨的許可權有限的資料庫連線。對隱私資訊進行加密
- DDOS 攻擊
分散式拒絕服務(DDoS:Distributed Denial of Service)攻擊指藉助於客戶/伺服器技術,將多個計算機聯合起來作為攻擊平臺,對一個或多個目標發動DDoS攻擊,從而成倍地提高拒絕服務攻擊的威力。
26. 用js實現陣列隨機取數,每次返回的值都不一樣
[參考答案]
function getUniqueItems(arr, num) {
let temp = [];
for (let index in arr) {
temp.push(arr[index]);
}
let res = [];
for (let i = 0; i<num; i++) {
if (temp.length>0) {
let arrIndex = Math.floor(Math.random()*temp.length);
res[i] = temp[arrIndex];
temp.splice(arrIndex, 1);
} else {
break;
}
}
return res;
}
複製程式碼
27. 頁面上有1萬個button如何繫結事件
[參考答案] 事件委託, 冒泡觸發
28. base64為什麼能提升效能以及它的缺點是什麼
[參考答案] 優點:
- 無額外請求
- 適用於很小或者很簡單的圖片
- 可像單獨圖片一樣使用,比如背景圖片等
- 沒有跨域問題,不需要考慮快取、檔案頭或者cookies問題 缺點:
- CSS 檔案體積的增大, 造成CRP(關鍵渲染路徑)阻塞
- 頁面解析CSS生成的CSSOM時間增加
29. 介紹webp圖片檔案格式
[參考答案]
WebP是一種支援有失真壓縮和無失真壓縮的圖片檔案格式,根據Google的測試,無失真壓縮後的WebP比PNG 檔案少了45%的檔案大小,即使這些PNG檔案經過其他壓縮工具壓縮之後,WebP 還是可以減少28%的檔案大小。
- 優點
- 更小的檔案尺寸
- 更高的質量——與其他相同大小不同格式的壓縮影像比較
- 缺點
- 編碼和解碼速度比較慢,存在一定相容性
30. react-router裡的Link標籤和a標籤有什麼區別
[參考答案]
從渲染的DOM來看,這兩者都是連結,都是a標籤,區別是: Link是react-router裡實現路由跳轉的連結,配合Route使用,react-router攔截了其預設的連結跳轉行為,區別於傳統的頁面跳轉,Link 的“跳轉”行為只會觸發相匹配的Route對應的頁面內容更新,而不會重新整理整個頁面。 a標籤是html原生的超連結,用於跳轉到href指向的另一個頁面或者錨點元素,跳轉新頁面會重新整理頁面。
31. 介紹一下函式柯里化,並寫一個柯里化函式
[參考答案]
柯里化是一種將使用多個引數的一個函式轉換成一系列使用一個引數的函式的技術。柯里化函式能夠讓我們:
- 在多個函式呼叫中依次收集引數,不用在一個函式呼叫中收集所有引數。
- 當收集到足夠的引數時,返回函式執行結果。
32. 介紹一下從輸入URL到頁面載入全過程
[參考答案]
- 瀏覽器的位址列輸入URL並按下回車。
- 瀏覽器查詢當前URL是否存在快取,並比較快取是否過期。
- DNS解析URL對應的IP。
- 根據IP建立TCP連線(三次握手)。
- HTTP發起請求。
- 伺服器處理請求,瀏覽器接收HTTP響應。
- 渲染頁面,構建DOM樹。
- 關閉TCP連線(四次揮手)。
33. 說說bind、call、apply的區別
[參考答案]
call和apply的共同點
- 都能夠改變函式執行時的上下文,將一個物件的方法交給另一個物件來執行,並且是立即執行的
- 呼叫call和apply的物件,必須是一個函式Function
call和apply的區別
- apply的第二個引數,必須是陣列或者類陣列,它會被轉換成類陣列,傳入函式中,並且會被對映到函式對應的引數上, 而call從第二個引數開始,可以接收任意個引數
bind
- bind()方法建立一個新的函式,與apply和call比較類似,也能改變函式體內的this指向。不同的是,bind方法的返回值是函式,並且需要稍後呼叫,才會執行。而apply和call 則是立即呼叫
34. ES6中的map和原生的物件有什麼區別
[參考答案]
object和Map儲存的都是鍵值對組合。區別:object的鍵的型別是字串;map的鍵的型別可以是任意型別;另外,object獲取鍵值使用Object.keys(返回陣列)Map獲取鍵值使用map變數.keys() (返回迭代器)。
35. 說說H5手機端的適配的幾種方案
[參考答案]
-
- js實現一
(function (doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = docEl.clientWidth;
var fontSize = 20;
docEl.style.fontSize = fontSize + 'px';
var docStyles = getComputedStyle(docEl);
var realFontSize = parseFloat(docStyles.fontSize);
var scale = realFontSize / fontSize;
console.log("realFontSize: " + realFontSize + ", scale: " + scale);
fontSize = clientWidth / 750 * 20;
if(isIphoneX()) fontSize = 19;
fontSize = fontSize / scale;
docEl.style.fontSize = fontSize + 'px';
};
// Abort if browser does not support addEventListener
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
// iphoneX判斷
function isIphoneX(){
return /iphone/gi.test(navigator.userAgent) && (screen.height == 812 && screen.width == 375)
}
})(document, window);
複製程式碼
-
- css @media媒介查詢(蘇寧易購實現方式)
-
- 手淘的lib-flexible實現方式
36. 用js如何去除url中的#號
[參考答案]
- 情景一: 單純將hash路由改變成history路由即可去除hash的#號,此時需要伺服器做路由重定向,比如nginx, node重定向
- 情景二: 單純去除#
function dropHash(url) {
let i = url.indexOf('#')
return i > -1 ? url.replace(/#/g, '') : url
}
複製程式碼
37. Redux狀態管理器和變數掛載到window中有什麼區別
[參考答案] redux通過制定一套嚴格的規範,提供一種規正規化的api和使用方式來處理狀態, 適合大型專案和多人協同開發的專案,雖然程式碼編寫有些繁複,但整體資料流向清楚,便於問題跟蹤和後期維護,並且支援狀態回溯.而window的變數管理比較混亂,維護不當還會造成變數汙染,不適合中大型專案的開發.
38. webpack和gulp的優缺點
[參考答案]
gulp | webpack | |
---|---|---|
定位 | 基於任務流的自動化打包工具 | 模組化打包工具 |
優點 | 易於學習和理解, 適合多頁面應用開發 | 可以模組化的打包任何資源,適配任何模組系統,適合SPA單頁應用的開發 |
缺點 | 不太適合單頁或者自定義模組的開發 | 學習成本低,配置複雜,通過babel編譯後的js程式碼打包後體積過大 |
39. 說說jsonp為什麼不支援post方法
[參考答案]
瀏覽器的同源策略限制從一個源載入的文件或指令碼與來自另一個源的資源進行互動,jsonp跨域本質上是通過動態script標籤, 本質上也是對靜態資源的訪問,所以只能是get請求
40. 說說棧和堆的區別, 垃圾回收時棧和堆的區別以及棧和堆具體怎麼儲存
[參考答案]
1.從定義和存取方式上說:
- 棧stack為自動分配的記憶體空間, 它由系統自動釋放, 特點是"LIFO,即後進先出(Last in, first out)"。資料儲存時只能從頂部逐個存入,取出時也需從頂部逐個取出,js的基本資料型別(Undefined、Null、Boolean、Number和String). 基本型別在記憶體中佔據空間小、大小固定 ,他們的值儲存在棧空間,按值訪問
- 堆heap是動態分配的記憶體,大小不定也不會自動釋放. 特點是"無序"的key-value"鍵值對"儲存方式. 比如js的物件,陣列. 引用型別佔據空間大、大小不固定, 棧記憶體中存放地址指向堆(heap)記憶體中的物件。是按引用訪問的
2.從js資料的存取過程上說:
棧記憶體中存放的是物件的訪問地址,在堆記憶體中為這個值分配空間。這個值大小不固定,因此不能把它們儲存到棧記憶體中。但記憶體地址大小的固定的,因此可以將記憶體地址儲存在棧記憶體中。這樣,當查詢引用型別的變數時,先從棧中讀取記憶體地址,然後再通過地址找到堆中的值。
3.棧記憶體和堆記憶體與垃圾回收機制的聯絡和清除方式:
- 垃圾回收機制: JavaScript中有自動垃圾回收機制,會通過標記清除的演算法識別哪些變數物件不再使用,對其進行銷燬。開發者也可在程式碼中手動設定變數值為null(xxx = null)進行清除,讓引用鏈斷開,以便下一次垃圾回收時有效回收。其次, 函式執行完成後,函式區域性環境宣告的變數不再需要時,就會被垃圾回收銷燬(理想的情況下,閉包會阻止這一過程)。全域性環境只有頁面退出時才會出棧,解除變數引用。所以工程師們應儘量避免在全域性環境中建立全域性變數,如需使用,一定要在不需要時手動標記清除,將記憶體釋放。
- 棧記憶體和堆記憶體通常與垃圾回收機制有關。之所以會區分棧記憶體和堆記憶體,目的是使程式執行時佔用的記憶體最小。當某個方法執行時,都會建立自己的記憶體棧,在這個方法內定義的變數將會逐個放入棧記憶體裡,隨著方法的執行結束,這個方法的記憶體棧也將自然銷燬了。因此,所有在方法中定義的變數都是放在棧記憶體中的;當我們建立一個物件時,物件會被儲存到執行時資料區中,以便反覆利用(因為物件的建立記憶體開銷較大),這個執行時資料區就是堆記憶體。堆記憶體中的物件不會隨方法的結束而銷燬,即使方法結束後,這個物件還可能被另一個引用變數所引用,則這個物件依然不會被銷燬,只有當一個物件沒有任何引用變數引用它時,系統的垃圾回收機制才會在迴圈收集的過程中回收。
41. ES6中let塊作用域是怎麼實現的
[參考答案]
可以通過閉包自執行函式實現塊作用域
42. 介紹排序演算法和快排原理
[參考答案]
排序演算法有:氣泡排序, 希爾排序, 快速排序, 插入排序, 歸併排序, 堆排序, 桶排序等.
快速排序原理:
通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。
43. 說說node檔案查詢的優先順序
[參考答案] 從檔案模組快取中載入 > 從原生模組載入 > 從檔案載入
44. WebView和原生是如何通訊的
[參考答案]
- 使用Android原生的JavascriptInterface來進行js和java的通訊
- UrlRouter(通過內部實現的框架去攔截前端寫的url,如果符合UrlRouter的協議的話,就執行相應的邏輯)
- WebView 中的 prompt/console/alert 攔截,通常使用 prompt避免副作用
- API注入,通過Native獲取JavaScript環境上下文,並直接在上面新增方法,使js可以直接呼叫
45. pm2怎麼做程式管理,如何解決程式奔潰問題
[參考答案]
- 通過pm2 start去開啟一個程式, pm2 stop去停止某個程式, pm2 list去檢視程式列表, pm2 monit檢視每個程式的cpu使用情況, pm2 restart重啟指定應用等
- 程式奔潰可以用過設定自動重啟或者限制應用執行記憶體max_memory_restart(最大記憶體限制數,超出自動重啟)
46. 直接給一個陣列項賦值,Vue 能檢測到變化嗎,為什麼?
[參考答案] vue中的陣列的監聽不是通過Object.defineProperty來實現的,是通過對'push', 'pop','shift','unshift','splice', 'sort','reverse'等改變陣列本身的方法來通知監聽的,所以直接給陣列某一項賦值無法監聽到變化,解決方案如下:
- 用vue的set方法改變陣列或者物件
- 用改變陣列本身的方法如splice, pop, shift等
- 用深拷貝,解構運算子
總結
面試只是進入公司的第一步,如何走好它,需要自身的不斷努力和學習,所以不要沉迷於走捷徑,踏踏實實的學技術吧. 年前筆者會總結一下筆者2019年的技術成長與規劃, 希望能和大家繼續分享真正的前端技術.
最後
如果想了解更多H5遊戲, webpack,node,gulp,css3,javascript,nodeJS,canvas資料視覺化等前端知識和實戰,歡迎在公眾號《趣談前端》加入我們一起學習討論,共同探索前端的邊界。
招聘
年後公司因擴招需要2-3名熟悉react的工程師,座標上海, 有意者請聯絡我哈~
更多推薦
- 2年vue專案實戰經驗彙總
- 15分鐘帶你瞭解前端工程師必知的javascript設計模式(附詳細思維導圖和原始碼)
- 《前端實戰總結》之使用純css實現網站換膚和焦點圖切換動畫
- 《前端實戰總結》之使用CSS3實現酷炫的3D旋轉透視
- 《前端實戰總結》之使用pace.js為你的網站新增載入進度條
- 《前端實戰總結》之設計模式的應用——備忘錄模式
- 《前端實戰總結》之使用postMessage實現可插拔的跨域聊天機器人
- 《前端實戰總結》之變數提升,函式宣告提升及變數作用域詳解
- 《前端實戰總結》如何在不重新整理頁面的情況下改變URL
- 一張圖教你快速玩轉vue-cli3
- vue高階進階系列——用typescript玩轉vue和vuex
- 基於nodeJS從0到1實現一個CMS全棧專案(上)
- 基於nodeJS從0到1實現一個CMS全棧專案(中)
- 基於nodeJS從0到1實現一個CMS全棧專案(下)
- 5分鐘教你用nodeJS手寫一個mock資料伺服器
- 用css3實現驚豔面試官的背景即背景動畫(高階附原始碼)
- 教你用200行程式碼寫一個偶像拼拼樂H5小遊戲(附原始碼)
- 笛卡爾乘積的javascript版實現和應用