您當前位置: 南順網絡>> 官方資訊>> 建站知識

我遇到的(de)前端面試題2017

想知道(dào)自(zì)己什麽水平就出去(qù)面試....

金九銀十,在九月之前把工作落實了,經曆了好幾個公司的(de)面試,得到一(yī)些信息,和(hé)大家分享:

  1. 大部分公司(創業公司)都趨向于招一(yī)個牛逼的(de)前端而不是三四個平庸的(de)前端

  2. 性能優化、ES6必問

  3. 招聘要求上清一(yī)色的(de)要求有一(yī)門後端語言的(de)經驗,但似乎面試的(de)時候并沒有一(yī)個公司問過我後端語言方面的(de)東西

  4. 招聘要求寫的(de)和(hé)面試相關性并不是很高(gāo)

  5. 招人的(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)防禦措施:

  1. 過濾轉義輸入輸出

  2. 避免使用eval、new Function等執行字符串的(de)方法,除非确定字符串和(hé)用戶輸入無關

  3. 使用cookie的(de)httpOnly屬性,加上了這個屬性的(de)cookie字段,js是無法進行讀寫的(de)

  4. 使用innerHTML、document.write的(de)時候,如(rú)果數據是用戶輸入的(de),那麽需要對象關鍵字符進行過濾與轉義

CSRF:跨站請求僞造
其實就是網站中的(de)一(yī)些提交行為(wèi),被黑客利用,在你訪問黑客的(de)網站的(de)時候進行操作,會被操作到其他網站上
CSRF防禦措施:

  1. 檢測http referer是否是同域名

  2. 避免登錄的(de)session長(cháng)時間存儲在客戶端中

  3. 關鍵請求使用驗證碼或者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

  1. let聲明的(de)變量擁有塊級作用域,let聲明仍然保留了提升的(de)特性,但不會盲目提升。

  2. let聲明的(de)全局變量不是全局對象的(de)屬性。不可(kě)以通過window.變量名的(de)方式訪問

  3. 形如(rú)for (let x…)的(de)循環在每次叠代時都為(wèi)x創建新的(de)綁定

  4. 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ī):

  1. content-box,默認值,border和(hé)padding不計算入width之內(nèi)

  2. padding-box,padding計算入width內(nèi)

  3. 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ī)張圖:

  1. HTML被解析成DOM Tree,CSS被解析成CSS Rule Tree

  2. 把DOM Tree和(hé)CSS Rule Tree經過整合生成Render Tree(布局階段)

  3. 元素按照算出來的(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是什麽

  1. Restful的(de)意思就是表現層狀态轉化。

  2. "表現層"其實指的(de)是"資源"(Resources)的(de)"表現層",把"資源"具體呈現出來的(de)形式,叫做(zuò)它的(de)"表現層"(Representation)。

  3. 所謂"資源",就是網絡上的(de)一(yī)個實體,或者說是網絡上的(de)一(yī)個具體信息。它可(kě)以是一(yī)段文本、一(yī)張圖片、一(yī)首歌曲、一(yī)種服務,總之就是一(yī)個具體的(de)實在,每一(yī)個URI代表一(yī)種資源。

  4. 如(rú)果客戶端想要操作服務器,必須通過某種手段,讓服務器端發生"狀态轉化"(State Transfer)。而這種轉化是建立在表現層之上的(de),所以就是"表現層狀态轉化"。

  5. Restful就是客戶端和(hé)服務器之間,傳遞這種資源的(de)某種表現層

  6. 客戶端通過四個HTTP動詞,對服務器端資源進行操作,實現"表現層狀态轉化"

Restful API就是符合Restful架構的(de)API設計。

Restful API一(yī)些具體實踐:

  1. 應該盡量将API部署在專用域名之下。如(rú)果确定API很簡單,不會有進一(yī)步擴展,可(kě)以考慮放在主域名下。

  2. 應該将API的(de)版本号放入URL。

  3. 對于資源的(de)具體操作類型,由HTTP動詞表示

  4. 如(rú)果記錄數量很多,服務器不可(kě)能都将它們返回給用戶。API應該提供參數,過濾返回結果

  5. 如(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)特性
閉包有三個特性:

  1. 函數嵌套函數

  2. 函數內(nèi)部可(kě)以引用外部的(de)參數和(hé)變量

  3. 參數和(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é)重繪

參考《如(rú)何寫出高(gāo)性能DOM?》

21.數組去(qù)重的(de)方法

參考:《JavaScript數組去(qù)重》

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。

    1. lodash,也有提供_.cloneDeep用來做(zuò) Deep Copy。

    2. 遞歸實現深拷貝

      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)實現:

  1. 用meta信息來告知浏覽器, 當前頁面要做(zuò)DNS預解析:<meta http-equiv="x-dns-prefetch-control" content="on" />

  2. 在頁面header中使用link标簽來強制對DNS預解析: <link rel="dns-prefetch" href="http://bdimg.share.baidu.com" />

25.HTTPS的(de)握手過程

  1. 浏覽器将自(zì)己支持的(de)一(yī)套加密規則發送給服務器。

  2. 服務器從中選出一(yī)組加密算法與HASH算法,并将自(zì)己的(de)身份信息以證書的(de)形式發回給浏覽器。證書裏面包含了網站地(dì)址,加密公鑰,以及證書的(de)頒發機構等信息。

  3. 浏覽器獲得網站證書之後浏覽器要做(zuò)以下工作:

    • 驗證證書的(de)合法

    • 如(rú)果證書受信任,或者是用戶接受了不受信的(de)證書,浏覽器會生成一(yī)串随機數的(de)密碼,并用證書中提供的(de)公鑰加密。

    • 使用約定好的(de)HASH算法計算握手消息,并使用生成的(de)随機數對消息進行加密,最後将之前生成的(de)所有信息發送給服務器

  4. 網站接收浏覽器發來的(de)數據之後要做(zuò)以下的(de)操作:

    • 使用自(zì)己的(de)私鑰将信息解密取出密碼,使用密碼解密浏覽器發來的(de)握手消息,并驗證HASH是否與浏覽器發來的(de)一(yī)緻。

    • 使用密碼加密一(yī)段握手消息,發送給浏覽器。

  5. 浏覽器解密并計算握手消息的(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