我遇到的(de)前端面試題2017
想知道(dào)自(zì)己什麽水平就出去(qù)面試....
金九銀十,在九月之前把工作落實了,經曆了好幾個公司的(de)面試,得到一(yī)些信息,和(hé)大家分享:
-
大部分公司(創業公司)都趨向于招一(yī)個牛逼的(de)前端而不是三四個平庸的(de)前端
-
性能優化、ES6必問
-
招聘要求上清一(yī)色的(de)要求有一(yī)門後端語言的(de)經驗,但似乎面試的(de)時候并沒有一(yī)個公司問過我後端語言方面的(de)東西
-
招聘要求寫的(de)和(hé)面試相關性并不是很高(gāo)
-
招人的(de)要求越來越高(gāo),不要輕易離(lí)職,特别是裸辭
以下是我整理(lǐ)我面試遇到的(de)一(yī)些我覺得具有代表性的(de)題目,剛好30題,吐血獻上!
0.談談對前端安全的(de)理(lǐ)解,有什麽,怎麽防範
前端安全問題主要有XSS、CSRF攻擊
XSS:跨站腳本攻擊
它允許用戶将惡意代碼植入到提供給其他用戶使用的(de)頁面中,可(kě)以簡單的(de)理(lǐ)解為(wèi)一(yī)種javascript代碼注入。
XSS的(de)防禦措施:
-
過濾轉義輸入輸出
-
避免使用eval、new Function等執行字符串的(de)方法,除非确定字符串和(hé)用戶輸入無關
-
使用cookie的(de)httpOnly屬性,加上了這個屬性的(de)cookie字段,js是無法進行讀寫的(de)
-
使用innerHTML、document.write的(de)時候,如(rú)果數據是用戶輸入的(de),那麽需要對象關鍵字符進行過濾與轉義
CSRF:跨站請求僞造
其實就是網站中的(de)一(yī)些提交行為(wèi),被黑客利用,在你訪問黑客的(de)網站的(de)時候進行操作,會被操作到其他網站上
CSRF防禦措施:
-
檢測http referer是否是同域名
-
避免登錄的(de)session長(cháng)時間存儲在客戶端中
-
關鍵請求使用驗證碼或者token機制
其他的(de)一(yī)些攻擊方法還有HTTP劫持、界面操作劫持
1.使用箭頭函數需要注意的(de)地(dì)方
當要求動态上下文的(de)時候,你就不能使用箭頭函數,比如(rú):定義方法,用構造器創建對象,處理(lǐ)時間時用 this 獲取目标。
2.webpack.load的(de)原理(lǐ)
loaders是你用在app源碼上的(de)轉換元件。他們是用node.js運行的(de),把源文件作為(wèi)參數,返回新的(de)資源的(de)函數。
3.ES6 let、const
let
let是更完美的(de)var
-
let聲明的(de)變量擁有塊級作用域,let聲明仍然保留了提升的(de)特性,但不會盲目提升。
-
let聲明的(de)全局變量不是全局對象的(de)屬性。不可(kě)以通過window.變量名的(de)方式訪問
-
形如(rú)for (let x…)的(de)循環在每次叠代時都為(wèi)x創建新的(de)綁定
-
let聲明的(de)變量直到控制流到達該變量被定義的(de)代碼行時才會被裝載,所以在到達之前使用該變量會觸發錯誤。
const
定義常量值,不可(kě)以重新賦值,但是如(rú)果值是一(yī)個對象,可(kě)以改變對象裏的(de)屬性值
const OBJ = {"a":1, "b":2};OBJ.a = 3;OBJ = {};// 重新賦值,報錯!console.log(OBJ.a); // 3
4.CSS3 box-sizing的(de)作用
設置CSS盒模型為(wèi)标準模型或IE模型。标準模型的(de)寬度隻包括content,二IE模型包括border和(hé)padding
box-sizing屬性可(kě)以為(wèi)三個值之一(yī):
-
content-box,默認值,border和(hé)padding不計算入width之內(nèi)
-
padding-box,padding計算入width內(nèi)
-
border-box,border和(hé)padding計算入width之內(nèi)
5.說說HTML5中有趣的(de)标簽(新标簽及語義化)
如(rú)果代碼寫的(de)語義化,有利于SEO。搜索引擎就會很容易的(de)讀懂該網頁要表達的(de)意思。例如(rú)文本模塊要有大标題,合理(lǐ)利用h1-h6,列表形式的(de)代碼使用ul或ol,重要的(de)文字使用strong等等。總之就是要充分利用各種HTML标簽完成他們本職的(de)工作
6.git命令,如(rú)何批量删除分支
git branch |grep 'branchName' |xargs git branch -D,從分支列表中匹配到指定分支,然後一(yī)個一(yī)個(分成小塊)傳遞給删除分支的(de)命令,最後進行删除。(參考這裏)
7.創建對象的(de)三種方法
第一(yī)種方式,字面量
var o1 = {name: "o1"}var o2 = new Object({name: "o2"})
第二種方式,通過構造函數
var M = function(name){ this.name = name }var o3 = new M("o3")
第三種方式,Object.create
var p = {name: "p"}var o4 = Object.create(p)
新創建的(de)對o4的(de)原型就是p,同時o4也擁有了屬性name
8.JS實現繼承的(de)幾種方式
借用構造函數實現繼承
function Parent1(){ this.name = "parent1"}function Child1(){ Parent1.call(this); this.type = "child1";}
缺點:Child1無法繼承Parent1的(de)原型對象,并沒有真正的(de)實現繼承(部分繼承)
借用原型鏈實現繼承
function Parent2(){ this.name = "parent2"; this.play = [1,2,3];}function Child2(){ this.type = "child2";}Child2.prototype = new Parent2();
缺點:原型對象的(de)屬性是共享的(de)
組合式繼承
function Parent3(){ this.name = "parent3"; this.play = [1,2,3];}function Child3(){ Parent3.call(this); this.type = "child3";}Child3.prototype = Object.create(Parent3.prototype);Child3.prototype.constructor = Child3;
9.當new Foo()時發生了什麽
1.創建了一(yī)個新對象
2.将this指向這個新對象
3.執行構造函數裏面的(de)代碼
4.返回新對象(this)
參考《JS高(gāo)程》6.6.2
10.你做(zuò)過哪些性能優化
雪碧圖,移動端響應式圖片,靜态資源CDN,減少Dom操作(事件代理(lǐ)、fragment),壓縮JS和(hé)CSS、HTML等,DNS預解析
11.浏覽器渲染原理(lǐ)
首先來看一(yī)張圖:
-
HTML被解析成DOM Tree,CSS被解析成CSS Rule Tree
-
把DOM Tree和(hé)CSS Rule Tree經過整合生成Render Tree(布局階段)
-
元素按照算出來的(de)規則,把元素放到它該出現的(de)位置,通過顯卡畫到屏幕上
更多詳情看這裏
12.前端路由的(de)原理(lǐ)
什麽是路由?簡單的(de)說,路由是根據不同的(de) url 地(dì)址展示不同的(de)內(nèi)容或頁面
使用場景?前端路由更多用在單頁應用上, 也就是SPA, 因為(wèi)單頁應用, 基本上都是前後端分離(lí)的(de), 後端自(zì)然也就不會給前端提供路由。
前端的(de)路由和(hé)後端的(de)路由在實現技術上不一(yī)樣,但是原理(lǐ)都是一(yī)樣的(de)。在 HTML5 的(de) history API 出現之前,前端的(de)路由都是通過 hash 來實現的(de),hash 能兼容低(dī)版本的(de)浏覽器。
兩種實現前端路由的(de)方式
HTML5 History兩個新增的(de)API:history.pushState 和(hé) history.replaceState,兩個 API 都會操作浏覽器的(de)曆史記錄,而不會引起頁面的(de)刷新。
Hash就是url 中看到 # ,我們需要一(yī)個根據監聽哈希變化觸發的(de)事件( hashchange) 事件。我們用 window.location 處理(lǐ)哈希的(de)改變時不會重新渲染頁面,而是當作新頁面加到曆史記錄中,這樣我們跳轉頁面就可(kě)以在 hashchange 事件中注冊 ajax 從而改變頁面內(nèi)容。
優點
從性能和(hé)用戶體驗的(de)層面來比較的(de)話,後端路由每次訪問一(yī)個新頁面的(de)時候都要向服務器發送請求,然後服務器再響應請求,這個過程肯定會有延遲。而前端路由在訪問一(yī)個新頁面的(de)時候僅僅是變換了一(yī)下路徑而已,沒有了網絡延遲,對于用戶體驗來說會有相當大的(de)提升。
更多內(nèi)容請看這裏
缺點
使用浏覽器的(de)前進,後退鍵的(de)時候會重新發送請求,沒有合理(lǐ)地(dì)利用緩存。
13.Restful API是什麽
-
Restful的(de)意思就是表現層狀态轉化。
-
"表現層"其實指的(de)是"資源"(Resources)的(de)"表現層",把"資源"具體呈現出來的(de)形式,叫做(zuò)它的(de)"表現層"(Representation)。
-
所謂"資源",就是網絡上的(de)一(yī)個實體,或者說是網絡上的(de)一(yī)個具體信息。它可(kě)以是一(yī)段文本、一(yī)張圖片、一(yī)首歌曲、一(yī)種服務,總之就是一(yī)個具體的(de)實在,每一(yī)個URI代表一(yī)種資源。
-
如(rú)果客戶端想要操作服務器,必須通過某種手段,讓服務器端發生"狀态轉化"(State Transfer)。而這種轉化是建立在表現層之上的(de),所以就是"表現層狀态轉化"。
-
Restful就是客戶端和(hé)服務器之間,傳遞這種資源的(de)某種表現層
-
客戶端通過四個HTTP動詞,對服務器端資源進行操作,實現"表現層狀态轉化"
Restful API就是符合Restful架構的(de)API設計。
Restful API一(yī)些具體實踐:
-
應該盡量将API部署在專用域名之下。如(rú)果确定API很簡單,不會有進一(yī)步擴展,可(kě)以考慮放在主域名下。
-
應該将API的(de)版本号放入URL。
-
對于資源的(de)具體操作類型,由HTTP動詞表示
-
如(rú)果記錄數量很多,服務器不可(kě)能都将它們返回給用戶。API應該提供參數,過濾返回結果
-
如(rú)果狀态碼是4xx,就應該向用戶返回出錯信息。一(yī)般來說,返回的(de)信息中将error作為(wèi)鍵名
.....
14.script标簽的(de)defer、async的(de)區别
defer是在HTML解析完之後才會執行,如(rú)果是多個,按照加載的(de)順序依次執行
async是在加載完成後立即執行,如(rú)果是多個,執行順序和(hé)加載順序無關
15.同源與跨域
什麽是同源策略?
限制從一(yī)個源加載的(de)文檔或腳本如(rú)何與來自(zì)另一(yī)個源的(de)資源進行交互。
一(yī)個源指的(de)是主機名、協議和(hé)端口号的(de)組合,必須相同
跨域通信的(de)幾種方式
-
JSONP
-
Hash
-
postMessage
-
WebSocket
-
CORS
JSONP原理(lǐ)
基本原理(lǐ):利用script标簽的(de)異步加載特性實現
給服務端傳一(yī)個回調函數,服務器返回一(yī)個傳遞過去(qù)的(de)回調函數名稱的(de)JS代碼
更多請查看:《前後端通信類知識》
16.原型與閉包相關問題
原型是什麽
原型就是一(yī)個普通的(de)對象,每個對象都有一(yī)個原型(Object除外),原型能存儲我們的(de)方法,構造函數創建出來的(de)實例對象能夠引用原型中的(de)方法。
查看原型
以前一(yī)般使用對象的(de)__proto__屬性,ES6推出後,推薦用Object.getPrototypeOf()方法來獲取對象的(de)原型
閉包是什麽?
專業說法:當一(yī)個內(nèi)部函數被其外部函數之外的(de)變量引用時,就形成了一(yī)個閉包。
還可(kě)以這麽理(lǐ)解:
閉包就是一(yī)個具有封閉功能與包裹功能的(de)結構,是為(wèi)了實現具有私有訪問空間的(de)函數的(de),函數可(kě)以構成閉包,因為(wèi)函數內(nèi)部定義的(de)數據函數外部無法訪問,即函數具有封閉性;函數可(kě)以封裝代碼即具有包裹性,所以函數可(kě)以構成閉包。
創建閉包的(de)最常見的(de)方式就是在一(yī)個函數內(nèi)創建另一(yī)個函數,通過另一(yī)個函數訪問這個函數的(de)局部變量
閉包的(de)特性
閉包有三個特性:
-
函數嵌套函數
-
函數內(nèi)部可(kě)以引用外部的(de)參數和(hé)變量
-
參數和(hé)變量不會被垃圾回收機制回收
閉包有什麽用,使用場景
當我們需要在模塊中定義一(yī)些變量,并希望這些變量一(yī)直保存在內(nèi)存中但又不會“污染”全局的(de)變量時,就可(kě)以用閉包來定義這個模塊。
閉包的(de)缺點
閉包的(de)缺點就是常駐內(nèi)存,會增大內(nèi)存使用量,使用不當很容易造成內(nèi)存洩露。
函數套函數就是閉包嗎?不是!,當一(yī)個內(nèi)部函數被其外部函數之外的(de)變量引用時,才會形成了一(yī)個閉包。
更多內(nèi)容請看這裏
17.如(rú)何進行錯誤監控
前端錯誤的(de)分類
-
即時運行錯誤(代碼錯誤)
-
資源加載錯誤
錯誤的(de)捕獲方式
即時運行錯誤的(de)捕獲方式:
-
try...catch
-
window.onerror
資源加載錯誤:
-
object.onerror(如(rú)img,script)
-
performance.getEntries()
-
Error事件捕獲
延伸:跨域的(de)js運行錯誤可(kě)以捕獲嗎,錯誤提示什麽,應該怎麽處理(lǐ)?
可(kě)以。
Script error
1.在script标簽增加crossorigin屬性
2.設置js資源響應頭Access-Control-Allow-Orgin:*
上報錯誤的(de)基本原理(lǐ)
采用Ajax通信方式上報
利用Image對象上報
18.DOM事件類
DOM事件的(de)級别
-
DOM0,element.onclick = function(){}
-
DOM2,element.addEventListener('click', function(){}, false);
DOM事件模型是什麽:指的(de)是冒泡和(hé)捕獲
DOM事件流是什麽:捕獲階段 -> 目标階段 -> 冒泡階段
描述DOM事件捕獲的(de)具體流程
window --> document --> documentElement(html标簽) --> body --> .... --> 目标對象
Event對象常見應用
-
event.preventDefault(),阻止默認行為(wèi)
-
event.stopPropagation(),阻止事件冒泡
-
event.stopImmediatePropagation(),阻止剩餘的(de)事件處理(lǐ)函數執行并且防止事件冒泡到DOM樹上,這個方法不接受任何參數。
-
event.currentTarget,返回綁定事件的(de)元素
-
event.target,返回觸發事件的(de)元素
如(rú)何自(zì)定義事件
Event,不能傳遞參數
var eve = new Event('自(zì)定義事件名');ev.addEventListener('自(zì)定義事件名', function(){ console.log('自(zì)定義事件')});ev.dispatchEvent(eve);
CustomEvent,還可(kě)以指定參數
19.本地(dì)起了一(yī)個http server,為(wèi)什麽隻能在同一(yī)個WIFI(局域網)上訪問?
你沒有公網IP當然就不能被外網訪問了。常見的(de)WIFI情況下,一(yī)般的(de)ip會是~192.168.0.x·這樣的(de),隻是對局域網(同WIFI下)可(kě)見,但是外網是訪問不了的(de)。(segmentfault上的(de)答案)
20.回流和(hé)重繪
21.數組去(qù)重的(de)方法
22.深拷貝與淺拷貝
是什麽
淺拷貝隻複制指向某個對象的(de)指針,而不複制對象本身,新舊(jiù)對象還是共享同一(yī)塊內(nèi)存。但深拷貝會另外創造一(yī)個一(yī)模一(yī)樣的(de)對象,新對象跟原對象不共享內(nèi)存,修改新對象不會改到原對象。
實現淺拷貝
var obj1 = { a: 10, b: 20, c: 30 };var obj2 = obj1;obj2.b = 100;console.log(obj1);// { a: 10, b: 100, c: 30 } <-- b 被改到了console.log(obj2);// { a: 10, b: 100, c: 30 }
實現深拷貝
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 } <-- b 沒被改到console.log(obj2);// { a: 10, b: 100, c: 30 }
深拷貝實現方式
-
手動複制方式,如(rú)上面的(de)代碼,缺點就是
-
Object.assign,ES6 的(de)新函數,可(kě)以幫助我們達成跟上面一(yī)樣的(de)功能。
var obj1 = { a: 10, b: 20, c: 30 };var obj2 = Object.assign({}, obj1);obj2.b = 100;console.log(obj1);// { a: 10, b: 20, c: 30 } <-- 沒被改到console.log(obj2);// { a: 10, b: 100, c: 30 }
-
轉成 JSON 再轉回來
用JSON.stringify把對象轉成字符串,再用JSON.parse把字符串轉成新的(de)對象。
缺點:隻有可(kě)以轉成JSON格式的(de)對象才可(kě)以這樣用,像function沒辦法轉成JSON。 -
jquery,有提供一(yī)個$.extend可(kě)以用來做(zuò) Deep Copy。
-
lodash,也有提供_.cloneDeep用來做(zuò) Deep Copy。
-
遞歸實現深拷貝
function clone( o ) {var temp = {};for( var k in o ) {if( typeof o[ k ] == 'object' ){ temp[ k ] = clone( o[ k ] );} else { temp[ k ] = o[ k ];}}return temp;}
參考文章(zhāng):關于 JS 中的(de)淺拷貝和(hé)深拷貝,進擊JavaScript之(四)玩轉遞歸與數列
23.如(rú)何快速合并雪碧圖
Gulp:gulp-css-spriter
webpack:optimize-css-assets-webpack-plugin
Go!Png
在線工具
24.代碼優化基本方法
減少HTTP請求
HTML優化:
-
使用語義化标簽
-
減少iframe:iframe是SEO的(de)大忌,iframe有好處也有弊端
-
避免重定向
CSS優化:
-
布局代碼寫前面
-
删除空樣式
-
不濫用浮動,字體,需要加載的(de)網絡字體根據網站需求再添加
-
選擇器性能優化
-
避免使用表達式,避免用id寫樣式
js優化:
-
壓縮
-
減少重複代碼
圖片優化:
-
使用WebP
-
圖片合并,CSS sprite技術
減少DOM操作
-
緩存已經訪問過的(de)元素
-
"離(lí)線"更新節點, 再将它們添加到樹中
-
避免使用 JavaScript 輸出頁面布局--應該是 CSS 的(de)事兒
使用JSON格式來進行數據交換
使用CDN加速
使用HTTP緩存:添加 Expires 或 Cache-Control 信息頭
使用DNS預解析
Chrome內(nèi)置了DNS Prefetching技術, Firefox 3.5 也引入了這一(yī)特性,由于Chrome和(hé)Firefox 3.5本身對DNS預解析做(zuò)了相應優化設置,所以設置DNS預解析的(de)不良影響之一(yī)就是可(kě)能會降低(dī)Google Chrome浏覽器及火狐Firefox 3.5浏覽器的(de)用戶體驗。
預解析的(de)實現:
-
用meta信息來告知浏覽器, 當前頁面要做(zuò)DNS預解析:<meta http-equiv="x-dns-prefetch-control" content="on" />
-
在頁面header中使用link标簽來強制對DNS預解析: <link rel="dns-prefetch" href="http://bdimg.share.baidu.com" />
25.HTTPS的(de)握手過程
-
浏覽器将自(zì)己支持的(de)一(yī)套加密規則發送給服務器。
-
服務器從中選出一(yī)組加密算法與HASH算法,并将自(zì)己的(de)身份信息以證書的(de)形式發回給浏覽器。證書裏面包含了網站地(dì)址,加密公鑰,以及證書的(de)頒發機構等信息。
-
浏覽器獲得網站證書之後浏覽器要做(zuò)以下工作:
-
驗證證書的(de)合法
-
如(rú)果證書受信任,或者是用戶接受了不受信的(de)證書,浏覽器會生成一(yī)串随機數的(de)密碼,并用證書中提供的(de)公鑰加密。
-
使用約定好的(de)HASH算法計算握手消息,并使用生成的(de)随機數對消息進行加密,最後将之前生成的(de)所有信息發送給服務器
-
網站接收浏覽器發來的(de)數據之後要做(zuò)以下的(de)操作:
-
使用自(zì)己的(de)私鑰将信息解密取出密碼,使用密碼解密浏覽器發來的(de)握手消息,并驗證HASH是否與浏覽器發來的(de)一(yī)緻。
-
使用密碼加密一(yī)段握手消息,發送給浏覽器。
-
浏覽器解密并計算握手消息的(de)HASH,如(rú)果與服務端發來的(de)HASH一(yī)緻,此時握手過程結束,之後所有的(de)通信數據将由之前浏覽器生成的(de)随機密碼并利用對稱加密算法進行加密。
參考文章(zhāng):《HTTPS 工作原理(lǐ)和(hé) TCP 握手機制》
26.BFC相關問題
BFC(Block formatting context)直譯為(wèi)"塊級格式化上下文"。它是一(yī)個獨立的(de)渲染區域,隻有 Block-level box 參 與, 它規定了內(nèi)部的(de) Block-level Box 如(rú)何布局,并且與這個區域外部毫不相幹。
BFC的(de)渲染規則
-
BFC這個元素的(de)垂直方向的(de)邊距會發生重疊
-
BFC的(de)區域不會與浮動元素的(de)box重疊(清除浮動原理(lǐ))
-
BFC在頁面上是一(yī)個獨立的(de)容器,外面的(de)元素不會影響它裏面的(de)元素,反過來它裏面的(de)元素也不會影響外面的(de)元素
-
計算BFC的(de)高(gāo)度的(de)時候,浮動元素也會參與計算
如(rú)何創建BFC?
-
overflow屬性不為(wèi)visible
-
float屬性不為(wèi)none
-
position屬性為(wèi)absolute或fixed
-
display屬性為(wèi)inline-block、table-cell、table-caption、flex、inline-flex
BFC的(de)使用場景
他的(de)很常用的(de)一(yī)個應用場景就是解決邊距重疊的(de)問題.
27.響應式圖片
1.JS或者服務端硬編碼,resize事件,判斷屏幕大小加載不同的(de)圖片
2.img srcset 方法
3.picture标簽 -> source
4.svg
5.第三方庫polyfill
28.判斷一(yī)個變量是否是數組
var a = []; // 1.基于instanceof a instanceof Array; // 2.基于constructor a.constructor === Array; // 3.基于Object.prototype.isPrototypeOf Array.prototype.isPrototypeOf(a); // 4.基于getPrototypeOf Object.getPrototypeOf(a) === Array.prototype; // 5.基于Object.prototype.toString Object.prototype.toString.apply(a) === '[object Array]';// 6.Array.isArrayArray.isArray([]); // true
以上,除了Object.prototype.toString外,其它方法都不能正确判斷變量的(de)類型。
29.UTF-8和(hé)Unicode的(de)區别
UTF-8就是在互聯網上使用最廣的(de)一(yī)種unicode的(de)實現方式。
Unicode的(de)出現是為(wèi)了統一(yī)地(dì)區性文字編碼方案,為(wèi)解決unicode如(rú)何在網絡上傳輸的(de)問題,于是面向傳輸的(de)衆多 UTF(UCS Transfer Format)标準出現了,顧名思義,UTF-8就是每次8個位傳輸數據,而UTF-16就是每次16個位。
編輯:--ns868