我遇到的前端面試題2017

圖片描述

本文首發於個人博客: http://blog.dunizb.com
原文連接: http://blog.dunizb.com/2017/09/08/interview-questions-2017/

轉載聲明
最近發現有人和網站盜用個人文章,有的轉載卻本身標爲原創,沒有明確顯示原文做者、原文出處及原文連接。個人網絡ID是:Dunizb。請自覺遵照網絡文章轉載規範以及開源協議。javascript

想知道本身什麼水平就出去面試,拋磚引玉,詳細答案還須要本身去補充....css

更新記錄html

  • 2019-07-28更新:修改第13題RESTful API的答案
  • 2018-06-12更新:修改第1題答案
  • 2017-10-19更新:修改22題深淺拷貝的答案
  • 2017-10-18更新:修正部分題目答案,答案並不是十分準確,僅供參考,此文部分題目答案故意省掉了一些高精尖、新奇特的東西,好比建立對象我寫了三種,《JS高程》上可不止三種,一切以經常使用記得住的爲宗旨,因此,對於部分答案有疑問的同窗,能夠留言討論或自行斟酌
  • 2017-10-12更新:有部分題目屬於後端範疇,或者是大前端範疇,由於我之前作Java後端的(關於我),故偶爾會遇到後端相關的一些問題,可是沒有遇到問純Java技術問題。若是你對某些後端題目不理解就直接跳過吧。

金九銀十,在九月以前把工做落實了,經歷了好幾個公司的面試,獲得一些信息,和你們分享:前端

  1. 大部分公司(創業公司)都趨向於招一個牛逼的前端而不是三四個平庸的前端
  2. 性能優化、ES6必問
  3. 招聘要求上清一色的要求有一門後端語言的經驗
  4. 招聘要求寫的和麪試相關性並非很高

如下是我整理我面試遇到的一些我以爲具備表明性的題目,恰好30題,吐血獻上!java

0.談談對前端安全的理解,有什麼,怎麼防範

前端安全問題主要有XSS、CSRF攻擊
XSS:跨站腳本攻擊
它容許用戶將惡意代碼植入到提供給其餘用戶使用的頁面中,能夠簡單的理解爲一種javascript代碼注入。
XSS的防護措施:node

  1. 過濾轉義輸入輸出
  2. 避免使用evalnew Function等執行字符串的方法,除非肯定字符串和用戶輸入無關
  3. 使用cookiehttpOnly屬性,加上了這個屬性的cookie字段,js是沒法進行讀寫的
  4. 使用innerHTMLdocument.write的時候,若是數據是用戶輸入的,那麼須要對象關鍵字符進行過濾與轉義

CSRF:跨站請求僞造
其實就是網站中的一些提交行爲,被黑客利用,在你訪問黑客的網站的時候進行操做,會被操做到其餘網站上
CSRF防護措施:jquery

  1. 檢測http referer是不是同域名
  2. 避免登陸的session長時間存儲在客戶端中
  3. 關鍵請求使用驗證碼或者token機制

其餘的一些攻擊方法還有HTTP劫持、界面操做劫持webpack

1.使用箭頭函數須要注意的地方

當要求動態上下文的時候,你就不能使用箭頭函數,好比:定義方法,用構造器建立對象,處理時間時用 this 獲取目標。git

箭頭函數與傳統函數的區別,主要集中在如下方面:web

  • 沒有this、super、arguments 和 new.target 綁定,這些值由最近一層非箭頭函數決定。
  • 不能經過 new 關鍵字調用,因此不能用做構造函數,不然程序會拋出錯誤(SyntaxError)。
  • 沒有原型。因爲不能夠經過new 關鍵字調用箭頭函數,於是沒有構建原型的需求,因此箭頭函數不存在 prototype 這個屬性。
  • 不能夠改變 this 的綁定,函數內部的 this 值不能夠被改變,在函數的生命週期內始終保持一致。
  • 不支持 arguments 對象,因此你必須經過命名參數和不定參數這兩種形式訪問函數的參數。
  • 不支持重複的命名參數,不管在嚴格仍是非嚴格模式下都不支持,而在傳統的函數規定中只有在嚴格模式下才不能有重複的命名參數。

2.webpack.load的原理

loaders是你用在app源碼上的轉換元件。他們是用node.js運行的,把源文件做爲參數,返回新的資源的函數。

3.ES6 let、const

let
let是更完美的var

  1. let聲明的變量擁有塊級做用域,let聲明仍然保留了提高的特性,但不會盲目提高。
  2. let聲明的全局變量不是全局對象的屬性。不能夠經過window.變量名的方式訪問
  3. 形如for (let x…)的循環在每次迭代時都爲x建立新的綁定
  4. let聲明的變量直到控制流到達該變量被定義的代碼行時纔會被裝載,因此在到達以前使用該變量會觸發錯誤。

const
定義常量值,不能夠從新賦值,可是若是值是一個對象,能夠改變對象裏的屬性值

const OBJ = {"a":1, "b":2};
OBJ.a = 3;
OBJ = {};// 從新賦值,報錯!
console.log(OBJ.a); // 3

4.CSS3 box-sizing的做用

設置CSS盒模型爲標準模型或IE模型。標準模型的寬度只包括content,二IE模型包括border和padding

box-sizing屬性能夠爲三個值之一:

  1. content-box,默認值,border和padding不計算入width以內
  2. padding-box,padding計算入width內
  3. border-box,border和padding計算入width以內

5.說說HTML5中有趣的標籤(新標籤及語義化)

若是代碼寫的語義化,有利於SEO。搜索引擎就會很容易的讀懂該網頁要表達的意思。例如文本模塊要有大標題,合理利用h1-h6,列表形式的代碼使用ul或ol,重要的文字使用strong等等。總之就是要充分利用各類HTML標籤完成他們本職的工做

6.git命令,如何批量刪除分支

git branch |grep 'branchName' |xargs git branch -D,從分支列表中匹配到指定分支,而後一個一個(分紅小塊)傳遞給刪除分支的命令,最後進行刪除。(參考這裏)

7.建立對象的三種方法

第一種方式,字面量

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)

新建立的對o4的原型就是p,同時o4也擁有了屬性name

8.JS實現繼承的幾種方式

借用構造函數實現繼承

function Parent1(){
    this.name = "parent1"
}
function Child1(){
    Parent1.call(this);
    this.type = "child1";
}

缺點:Child1沒法繼承Parent1的原型對象,並無真正的實現繼承(部分繼承)

借用原型鏈實現繼承

function Parent2(){
    this.name = "parent2";
    this.play = [1,2,3];
}
function Child2(){
    this.type = "child2";
}
Child2.prototype = new Parent2();

缺點:原型對象的屬性是共享的

組合式繼承

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.建立了一個新對象
2.將新建立的空對象的隱式原型指向其構造函數的顯示原型。
3.將this指向這個新對象
4.若是無返回值或者返回一個非對象值,則將新對象返回;若是返回值是一個新對象的話那麼直接直接返回該對象。
參考《JS高程》6.2.2

10.你作過哪些性能優化

雪碧圖,移動端響應式圖片,靜態資源CDN,減小Dom操做(事件代理、fragment),壓縮JS和CSS、HTML等,DNS預解析

11.瀏覽器渲染原理

首先來看一張圖:

  1. HTML被解析成DOM Tree,CSS被解析成CSS Rule Tree
  2. 把DOM Tree和CSS Rule Tree通過整合生成Render Tree(佈局階段)
  3. 元素按照算出來的規則,把元素放到它該出現的位置,經過顯卡畫到屏幕上
更多詳情看 這裏

12.前端路由的原理

什麼是路由?簡單的說,路由是根據不一樣的 url 地址展現不一樣的內容或頁面

使用場景?前端路由更多用在單頁應用上, 也就是SPA, 由於單頁應用, 基本上都是先後端分離的, 後端天然也就不會給前端提供路由。

前端的路由和後端的路由在實現技術上不同,可是原理都是同樣的。在 HTML5 的 history API 出現以前,前端的路由都是經過 hash 來實現的,hash 能兼容低版本的瀏覽器。

兩種實現前端路由的方式
HTML5 History兩個新增的API:history.pushStatehistory.replaceState,兩個 API 都會操做瀏覽器的歷史記錄,而不會引發頁面的刷新。

Hash就是url 中看到 # ,咱們須要一個根據監聽哈希變化觸發的事件( hashchange) 事件。咱們用 window.location 處理哈希的改變時不會從新渲染頁面,而是看成新頁面加到歷史記錄中,這樣咱們跳轉頁面就能夠在 hashchange 事件中註冊 ajax 從而改變頁面內容。

優勢
從性能和用戶體驗的層面來比較的話,後端路由每次訪問一個新頁面的時候都要向服務器發送請求,而後服務器再響應請求,這個過程確定會有延遲。而前端路由在訪問一個新頁面的時候僅僅是變換了一下路徑而已,沒有了網絡延遲,對於用戶體驗來講會有至關大的提高。

更多內容請看 這裏

缺點
使用瀏覽器的前進,後退鍵的時候會從新發送請求,沒有合理地利用緩存。

13.Restful API是什麼,如何設計RESTful API?

RESTful API是指符合REST設計風格的Web API,爲了使的接口安全、易用、可維護以及可擴張,通常設計RESTful API須要考慮如下幾個方面:

  1. 通訊用HTTPS安全協議
  2. 在URL中加入版本號
  3. URL中的路徑不能有動詞,只能用名詞
  4. 用HTTP方法對資源進行增刪改查的操做
  5. 用HTTP狀態嗎傳達執行結果和失敗緣由
  6. 爲集合提供過濾、排序、分頁功能
  7. 用查詢字符串或HTTP首部Accpet進行內容協商,指定返回結果的數據格式
  8. 及時更新文檔,每一個接口都有對應的說明

14.script標籤的defer、async的區別

defer是在HTML解析完以後纔會執行,若是是多個,按照加載的順序依次執行
async是在加載完成後當即執行,若是是多個,執行順序和加載順序無關

15.同源與跨域

什麼是同源策略?
限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。
一個源指的是主機名、協議和端口號的組合,必須相同

跨域通訊的幾種方式

  • JSONP
  • Hash
  • postMessage
  • WebSocket
  • CORS

JSONP原理
基本原理:利用script標籤的異步加載特性實現
給服務端傳一個回調函數,服務器返回一個傳遞過去的回調函數名稱的JS代碼

更多請查看: 《先後端通訊類知識》

16.做用域與閉包、原型相關問題

16.1 做用域

域表示的就是範圍,即做用域,就是一個名字在什麼地方可使用,何時不能使用。
簡單的說,做用域是針對變量的,好比咱們建立一個函數 a1,函數裏面又包了一個子函數 a2

// 全局做用域
functiona a1() {
    // a1做用域
    function a2() {
        // a2做用域
    }
}

此時就存 在三個做用域:全局做用域,a1 做用域,a2 做用域;即全局做用域包含了 a1 的做用域,a2 的做用域包含了 a1 的做用域。

a2 在查找變量的時候會先從自身的做用域區查找,找不到再到上一級 a1 的做用域查找,若是還沒找到就到全局做用域區查找,這樣就造成了一個做用域鏈

16.2 閉包

什麼是閉包?
當一個內部函數被其外部函數以外的變量引用時,就造成了一個閉包。

簡單的來講,所謂的閉包就是一個具備封閉的對外不公開的,包裹結構或空間。

爲何函數能夠構成閉包?
閉包就是一個具備封閉與包裹功能的結構,是爲了實現具備私有訪問空間的函數的。函數能夠構成閉包。函數內部定義的數據函數外部沒法訪問,即函數具備封閉性;函數能夠封裝代碼即具備包裹性,因此函數能夠構成閉包。

16.3 閉包有什麼用(特性)

閉包的做用,就是保存本身私有的變量,經過提供的接口(方法)給外部使用,但外部不能直接訪問該變量。

當咱們須要在模塊中定義一些變量,並但願這些變量一直保存在內存中但又不會「污染」全局的變量時,就能夠用閉包來定義這個模塊。

閉包的缺點:閉包的缺點就是常駐內存,會增大內存使用量,使用不當很容易形成內存泄露。

函數套函數就是閉包嗎?:不是!,當一個內部函數被其外部函數以外的變量引用時,纔會造成了一個閉包。

16.4 閉包的基本模型

對象模式
函數內部定義個一個對象,對象中綁定多個函數(方法),返回對象,利用對象的方法訪問函數內的數據

function createPerson() {
    var __name__ = "";
    return {
        getName: function () {
            return __name__;
        },
        setName: function( value ) {
            // 若是不姓張就報錯
            if ( value.charAt(0) === '張' ) {
                __name__ = value;
            } else {
                throw new Error( '姓氏不對,不能取名' );
            }
        }
    }
}
var p = createPerson();
p.set_Name( '張三丰' );
console.log( p.get_Name() );
p.set_Name( '張王富貴' );
console.log( p.get_Name() );

函數模式
函數內部定義一個新函數,返回新函數,用新函數得到函數內的數據

function foo() {
    var num = Math.random();
    function func() {
        return mun;
    }
    return func;
}
var f = foo();
// f 能夠直接訪問這個 num
var res1 = f();
var res2 = f();

沙箱模式
沙箱模式就是一個自調用函數,代碼寫到函數中同樣會執行,可是不會與外界有任何的影響,好比jQuery

(function () {
   var jQuery = function () { // 全部的算法 }
   // .... // .... jQuery.each = function () {}
   window.jQuery = window.$ = jQuery;
})();
$.each( ... )

原型

原型是什麼
原型就是一個普通的對象,每一個對象都有一個原型(Object除外),原型能存儲咱們的方法,構造函數建立出來的實例對象可以引用原型中的方法。

查看原型
之前通常使用對象的__proto__屬性,ES6推出後,推薦用Object.getPrototypeOf()方法來獲取對象的原型

什麼是原型鏈?
凡是對象就有原型,那麼原型又是對象,所以凡是給定一個對象,那麼就能夠找到他的原型,原型還有原型,那麼如此下去,就構成一個對象的序列,稱該結構爲原型鏈。

更多內容請看 這裏

17.如何進行錯誤監控

前端錯誤的分類

  • 即時運行錯誤(代碼錯誤)
  • 資源加載錯誤

錯誤的捕獲方式
即時運行錯誤的捕獲方式:

  • try...catch
  • window.onerror

資源加載錯誤:

  • object.onerror(如img,script)
  • performance.getEntries()
  • Error事件捕獲
延伸:跨域的js運行錯誤能夠捕獲嗎,錯誤提示什麼,應該怎麼處理?
能夠。
Script error
1.在script標籤增長crossorigin屬性
2.設置js資源響應頭Access-Control-Allow-Orgin:*

上報錯誤的基本原理
採用Ajax通訊方式上報
利用Image對象上報

18.DOM事件類

DOM事件的級別

  • DOM0,element.onclick = function(){}
  • DOM2,element.addEventListener('click', function(){}, false);

DOM事件模型是什麼:指的是冒泡和捕獲
DOM事件流是什麼:捕獲階段 -> 目標階段 -> 冒泡階段
描述DOM事件捕獲的具體流程
window --> document --> documentElement(html標籤) --> body --> .... --> 目標對象
Event對象常見應用

  • event.preventDefault(),阻止默認行爲
  • event.stopPropagation(),阻止事件冒泡
  • event.stopImmediatePropagation(),阻止剩餘的事件處理函數執行而且防止事件冒泡到DOM樹上,這個方法不接受任何參數。
  • event.currentTarget,返回綁定事件的元素
  • event.target,返回觸發事件的元素

如何自定義事件
Event,不能傳遞參數

var eve = new Event('自定義事件名');
ev.addEventListener('自定義事件名', function(){
    console.log('自定義事件')
});
ev.dispatchEvent(eve);

CustomEvent,還能夠指定參數

19.本地起了一個http server,爲何只能在同一個WIFI(局域網)上訪問?

你沒有公網IP固然就不能被外網訪問了。常見的WIFI狀況下,通常的ip會是~192.168.0.x·這樣的,只是對局域網(同WIFI下)可見,可是外網是訪問不了的。(segmentfault上的答案

20.迴流和重繪

參考《如何寫出高性能DOM?》

21.數組去重的方法

參考:《JavaScript數組去重》

22.深拷貝與淺拷貝

是什麼
淺拷貝只複製指向某個對象的指針,而不復制對象自己,新舊對象仍是共享同一塊內存(內存區域沒有隔離)。但深拷貝會另外創造一個如出一轍的對象,新對象跟原對象不共享內存(內存區域隔離),修改新對象不會改到原對象。在多層對象上,淺拷貝只拷貝一層
淺拷貝舉例

var Chinese = {
  nation:'中國'
};
var Doctor ={
  career:'醫生'
}
function extendCopy(p) {
  var c = {};
  for (var i in p) { 
    c[i] = p[i];
  }
  return c;
}
var Doctor = extendCopy(Chinese);
Doctor.career = '醫生';
alert(Doctor.nation); // 中國

深拷貝舉例

function deepCopy(p, c) {
  var c = c || {};
  for (var i in p) {
    if (typeof p[i] === 'object') {
      c[i] = (p[i].constructor === Array) ? [] : {};
      deepCopy(p[i], c[i]);
    } else {
      c[i] = p[i];
    }
  }
  return c;
}

參考文章:阮一峯:Javascript面向對象編程(三):非構造函數的繼承

深拷貝實現方式

  • 手動複製方式,如上面的代碼,缺點就是
  • Object.assign,ES6 的新函數,能夠幫助咱們達成跟上面同樣的功能。
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把字符串轉成新的對象。
缺點:只有能夠轉成JSON格式的對象才能夠這樣用,像function沒辦法轉成JSON。

  • jquery,有提供一個$.extend能夠用來作 Deep Copy。
  1. lodash,也有提供_.cloneDeep用來作 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;
}

參考文章:關於 JS 中的淺拷貝和深拷貝,進擊JavaScript之(四)玩轉遞歸與數列

23.如何快速合併雪碧圖

  • Gulp:gulp-css-spriter
  • webpack:optimize-css-assets-webpack-plugin
  • Go!Png
  • 在線工具

24.代碼優化基本方法

減小HTTP請求
HTML優化:

  • 使用語義化標籤
  • 減小iframe:iframe是SEO的大忌,iframe有好處也有弊端
  • 避免重定向

CSS優化:

  • 佈局代碼寫前面
  • 刪除空樣式
  • 不濫用浮動,字體,須要加載的網絡字體根據網站需求再添加
  • 選擇器性能優化
  • 避免使用表達式,避免用id寫樣式

js優化:

  • 壓縮
  • 減小重複代碼

圖片優化:

  • 使用WebP
  • 圖片合併,CSS sprite技術

減小DOM操做

  • 緩存已經訪問過的元素
  • "離線"更新節點, 再將它們添加到樹中
  • 避免使用 JavaScript 輸出頁面佈局--應該是 CSS 的事兒

使用JSON格式來進行數據交換
使用CDN加速
使用HTTP緩存:添加 ExpiresCache-Control 信息頭
使用DNS預解析
Chrome內置了DNS Prefetching技術, Firefox 3.5 也引入了這一特性,因爲Chrome和Firefox 3.5自己對DNS預解析作了相應優化設置,因此設置DNS預解析的不良影響之一就是可能會下降Google Chrome瀏覽器及火狐Firefox 3.5瀏覽器的用戶體驗。
預解析的實現:

  1. 用meta信息來告知瀏覽器, 當前頁面要作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的握手過程

  1. 瀏覽器將本身支持的一套加密規則發送給服務器。
  2. 服務器從中選出一組加密算法與HASH算法,並將本身的身份信息以證書的形式發回給瀏覽器。證書裏面包含了網站地址,加密公鑰,以及證書的頒發機構等信息。
  3. 瀏覽器得到網站證書以後瀏覽器要作如下工做:

    • 驗證證書的合法
    • 若是證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機數的密碼,並用證書中提供的公鑰加密。
    • 使用約定好的HASH算法計算握手消息,並使用生成的隨機數對消息進行加密,最後將以前生成的全部信息發送給服務器
  4. 網站接收瀏覽器發來的數據以後要作如下的操做:

    • 使用本身的私鑰將信息解密取出密碼,使用密碼解密瀏覽器發來的握手消息,並驗證HASH是否與瀏覽器發來的一致。
    • 使用密碼加密一段握手消息,發送給瀏覽器。
  5. 瀏覽器解密並計算握手消息的HASH,若是與服務端發來的HASH一致,此時握手過程結束,以後全部的通訊數據將由以前瀏覽器生成的隨機密碼並利用對稱加密算法進行加密。

參考文章:《HTTPS 工做原理和 TCP 握手機制》

26.BFC相關問題

BFC(Block formatting context)直譯爲"塊級格式化上下文"。它是一個獨立的渲染區域,只有 Block-level box 參 與, 它規定了內部的 Block-level Box 如何佈局,而且與這個區域外部絕不相干。

BFC的渲染特色

  • BFC這個元素的垂直方向的邊距會發生重疊,垂直方向的距離由margin決定,取最大值
  • BFC的區域不會與浮動元素的box重疊(清除浮動原理
  • 計算BFC的高度的時候,浮動元素也會參與計算

哪些元素會生成 BFC

BFC 就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此。

  • 根元素
  • overflow不爲visible
  • float不爲none
  • position爲absolute或fixed
  • display爲inline-block、table-cell、table-caption、flex、inline-flex

BFC的使用場景

他的很經常使用的一個應用場景就是解決邊距重疊、清楚浮動的問題.

27.響應式圖片

1.JS或者服務端硬編碼,resize事件,判斷屏幕大小加載不一樣的圖片
2.img srcset 方法
3.picture標籤 -> source
4.svg
5.第三方庫polyfill

28.判斷一個變量是不是數組

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.isArray
Array.isArray([]); // true

以上,除了Object.prototype.toString外,其它方法都不能正確判斷變量的類型。

29.UTF-8和Unicode的區別

UTF-8就是在互聯網上使用最廣的一種unicode的實現方式。
Unicode的出現是爲了統一地區性文字編碼方案,爲解決unicode如何在網絡上傳輸的問題,因而面向傳輸的衆多 UTF(UCS Transfer Format)標準出現了,顧名思義,UTF-8就是每次8個位傳輸數據,而UTF-16就是每次16個位。
ASCII --> 地區性編碼(GBK) --> Unicode --> UTF-8
知乎參考回答


參考
慕課網實戰課程《前端跳槽面試必備技巧》

相關文章
相關標籤/搜索