前端面試基礎篇,凜冬將至!道友快來一塊兒閉關修煉!

借用神劇《權遊》的名句:「凜冬將至!」,互聯網寒冬已然來臨,這一年以來keep/滴滴/京東/騰訊/華爲等大廠裁人事件不斷爆出!驚醒着頭髮慢慢脫落、變少的咱們,是時候閉關修煉了!javascript

本文爲前端面試基礎篇,將以 面試題 && 答案【參考 (๑¯∀¯๑)】的形式,閉關修煉,但願你查漏補缺,完善你的知識體系!css

面試,咱們是認真的!

JavaScript 篇

1. JavaScript有⼏種類型的值

  • 棧:原始數據類型( Undefined , Null , Boolean , Number 、 String
  • 堆:引⽤數據類型(對象、數組和函數)
  • 兩種類型的區別是:存儲位置不一樣
    • 原始數據類型直接存儲在棧( stack )中的簡單數據段,佔據空間⼩、⼤⼩固定,屬於被頻 繁使⽤數據,因此放⼊棧中存儲;
    • 引⽤數據類型存儲在堆( heap )中的對象,佔據空間⼤、⼤⼩不固定,若是存儲在棧中,將會 影響程序運⾏的性能;引⽤數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地 址。當解釋器尋找引⽤值時,會⾸先檢索其 在棧中的地址,取得地址後從堆中得到實體

2. 介紹JavaScript有哪些內置對象

  • Object 是 JavaScript 中全部對象的⽗對象
  • 數據封裝類對象: Object 、 Array 、 Boolean 、 Number 和 String
  • 其餘對象: Function 、 Arguments 、 Math 、 Date 、 RegExp 、 Error

3. null,undefined 的區別

  • undefined 表示不存在這個值
  • undefined : 是⼀個表示"⽆"的原始值或者說表示"缺乏值",就是此處應該有⼀個值,但 是尚未定義。 例如變量被聲明瞭,但沒有賦值時,就等於 undefined
  • null 表示⼀個對象被定義了,值爲「空值」
  • null : 是⼀個對象(空對象, 沒有任何屬性和⽅法) 例如做爲函數的參數,表示該函數的參數不是對象; 在驗證 null 時,⼀定要使⽤ === ,由於 == ⽆法分別 null 和 undefined

4. 什麼是事件代理

  • 事件代理( Event Delegation ),⼜稱之爲事件委託。是 JavaScript 中綁定事件的常⽤技巧。顧名思義,「事件代理」便是把本來須要綁定的事件委託給⽗元素,讓⽗元素擔當事件監聽的職務。事件代理的原理是DOM元素的事件冒泡。
  • 使⽤事件代理的好處是:
    • 能夠提⾼性能
    • 能夠⼤量節省內存佔⽤
    • 減小事件註冊,⽐如在 table 上代理全部 td 的 click 事件

5. 同步和異步的區別

  • 同步:瀏覽器訪問服務器請求,⽤戶看獲得⻚⾯刷新,從新發請求,等請求完,⻚⾯刷新, 新內容出現,⽤戶看到新內容,進⾏下⼀步操做
  • 異步:瀏覽器訪問服務器請求,⽤戶正常操做,瀏覽器後端進⾏請求。等請求完,⻚⾯不 刷新,新內容也會出現,⽤戶看到新內容

6. defer 和 async

  • defer 並⾏加載 js ⽂件,會按照⻚⾯上 script 標籤的順序執⾏
  • async 並⾏加載 js ⽂件,下載完成⽴即執⾏,不會按照⻚⾯上 script 標籤的順序執 ⾏

7. 什麼是⾯向對象編程和⾯向過程編程

  • ⾯向過程就是分析出解決問題所須要的步驟,而後⽤函數把這些步驟⼀步⼀步實現,使⽤ 的時候⼀個⼀個依次調⽤就能夠了
  • ⾯向對象是把構成問題事務分解成各個對象,建⽴對象的⽬的不是爲了完成⼀個步驟,⽽ 是爲了描敘某個事物在整個解決問題的步驟中的⾏爲 ⾯向對象是以功能來劃分問題,⽽不是步驟

8. ⾯向對象編程思想

  • 基本思想是使⽤對象,類,繼承,封裝等基本概念來進⾏程序設計html

  • 優勢前端

    • 易維護 採⽤⾯向對象思想設計的結構,可讀性⾼,因爲繼承的存在,即便改變需求,那麼維 護也只是在局部模塊,因此維護起來是⾮常⽅便和較低成本的
    • 易擴展
    • 開發⼯做的重⽤性、繼承性⾼,下降重複⼯做量
    • 縮短了開發週期

9. Javascript中callee和caller的做⽤?

  • caller 是返回⼀個對函數的引⽤,該函數調⽤了當前函數;
  • callee 是返回正在被執⾏的 function 函數,也就是所指定的 function 對象的正⽂

10. 事件的各個階段

  • 1:捕獲階段 ---> 2:⽬標階段 ---> 3:冒泡階段
  • document ---> target ⽬標 ----> document
  • 由此, addEventListener 的第三個參數設置爲 true 和 false 的區別已經⾮常清晰了
    • true 表示該元素在事件的「捕獲階段」(由外往內傳遞時)響應事件
    • false 表示該元素在事件的「冒泡階段」(由內向外傳遞時)響應事件

11. 閉包

  • 閉包就是可以讀取其餘函數內部變量的函數
  • 閉包是指有權訪問另⼀個函數做⽤域中變量的函數,建立閉包的最常⻅的⽅式就是在⼀個 函數內建立另⼀個函數,經過另⼀個函數訪問這個函數的局部變量,利⽤閉包能夠突破做⽤鏈域
  • 閉包的特性:
    • 函數內再嵌套函數
    • 內部函數能夠引⽤外層的參數和變量
    • 參數和變量不會被垃圾回收機制回收

說說你對閉包的理解java

  • 使⽤閉包主要是爲了設計私有的⽅法和變量。閉包的優勢是能夠避免全局變量的污染,缺點是閉包會常駐內存,會增⼤內存使⽤量,使⽤不當很容易形成內存泄露。在js中,函數即 閉包,只有函數纔會產⽣做⽤域的概念node

  • 閉包的最⼤⽤處有兩個,⼀個是能夠讀取函數內部的變量,另⼀個就是讓這些變量始終保持在內存中ios

  • 閉包的另⼀個⽤處,是封裝對象的私有屬性和私有⽅法nginx

  • 好處:可以實現封裝和緩存等;es6

  • 壞處:就是消耗內存、不正當使⽤會形成內存溢出的問題 使⽤閉包的注意點web

  • 因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很⼤,因此不能濫⽤閉包,否 則會形成⽹⻚的性能問題,在IE中可能致使內存泄露

  • 解決⽅法是,在退出函數以前,將不使⽤的局部變量所有刪除

12. 說說你對做⽤域鏈的理解

  • 做⽤域鏈的做⽤是保證執⾏環境⾥有權訪問的變量和函數是有序的,做⽤域鏈的變量只能 向上訪問,變量訪問到 window 對象即被終⽌,做⽤域鏈向下訪問變量是不被容許的
  • 簡單的說,做⽤域就是變量與函數的可訪問範圍,即做⽤域控制着變量與函數的可⻅性和 ⽣命週期

13. JavaScript原型,原型鏈 ? 有什麼特色?

  • 每一個對象都會在其內部初始化⼀個屬性,就是 prototype (原型),當咱們訪問⼀個對象的屬性時
  • 若是這個對象內部不存在這個屬性,那麼他就會去 prototype ⾥找這個屬性,這個 prototype ⼜會有⾃⼰的 prototype ,因而就這樣⼀直找下去,也就是咱們平時所說的原型鏈的概念
  • 關係: instance.constructor.prototype = instance._proto_
  • 特色:
  • JavaScript 對象是經過引⽤來傳遞的,咱們建立的每一個新對象實體中並無⼀份屬於 ⾃⼰的原型副本。當咱們修改原型時,與之相關的對象也會繼承這⼀改變
  • 當咱們須要⼀個屬性的時, Javascript 引擎會先看當前對象中是否有這個屬性, 若是沒有的就會查找他的 Prototype 對象是否有這個屬性,如此遞推下去,⼀直檢索到 Object 內 建對象

14. Javascript如何實現繼承?

  • 構造繼承
  • 原型繼承
  • 實例繼承
  • 拷⻉繼承
  • 原型 prototype 機制或 apply 和 call ⽅法去實現較簡單,建議使⽤構造函數與原型混合⽅式
function Parent(){
    this.name = 'wang'; }
    function Child(){
    this.age = 28; }
    Child.prototype = new Parent(); // 經過原型繼承了Parent
    var demo = new Child();
    console.log(demo.age);
    console.log(demo.name); // 獲得被繼承的屬性
    
複製代碼

15. javascript有哪些⽅法定義對象

  • 對象字⾯量: var obj = {};
  • 構造函數: var obj = new Object();
  • Object.create(): var obj = Object.create(Object.prototype);

16. 談談This對象的理解

  • this 老是指向函數的直接調⽤者(⽽⾮間接調⽤者)
  • 若是有 new 關鍵字, this 指向 new 出來的那個對象
  • 在事件中, this 指向觸發這個事件的對象,特殊的是, IE 中的 attachEvent 中的 this 老是指向全局對象 Window

17. new操做符具體⼲了什麼呢?

  • 建立⼀個空對象,而且 this 變量引⽤該對象,同時還繼承了該函數的原型
  • 屬性和⽅法被加⼊到 this 引⽤的對象中
  • 新建立的對象由 this 所引⽤,而且最後隱式的返回 this

18. 那些操做會形成內存泄漏?

  • 內存泄漏指任何對象在您再也不擁有或須要它以後仍然存在
  • setTimeout 的第⼀個參數使⽤字符串⽽⾮函數的話,會引起內存泄漏
  • 閉包使⽤不當

19. Ajax原理

  • Ajax 的原理簡單來講是在⽤戶和服務器之間加了—箇中間層( AJAX 引擎),經過 XmlHttpRequest 對象來向服務器發異步請求,從服務器得到數據,而後⽤ javascrip t 來操做 DOM ⽽更新⻚⾯。使⽤戶操做與服務器響應異步化。這其中最關鍵的⼀步就是從服 務器得到請求數據
  • Ajax 的過程只涉及 JavaScript 、 XMLHttpRequest 和 DOM 。 XMLHttpRequest 是 aja x的核⼼機制
/** 1. 建立鏈接 **/
    let xhr = null;
    xhr = new XMLHttpRequest()
    /** 2. 鏈接服務器 **/
    xhr.open('get', url, true)
    /** 3. 發送請求 **/
    xhr.send(null);
    /** 4. 接受請求 **/
    xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
    if(xhr.status == 200){
    success(xhr.responseText); } else {
    /** false **/
    fail && fail(xhr.status); } } }
    
複製代碼

ajax 有那些優缺點?

  • 優勢:
    • 經過異步模式,提高了⽤戶體驗.
    • 優化了瀏覽器和服務器之間的傳輸,減小沒必要要的數據往返,減小了帶寬佔⽤.
    • Ajax 在客戶端運⾏,承擔了⼀部分原本由服務器承擔的⼯做,減小了⼤⽤戶量下的服 務器負載。 Ajax 能夠實現動態不刷新(局部刷新)
  • 缺點:
    • 安全問題 AJAX 暴露了與服務器交互的細節。
    • 對搜索引擎的⽀持⽐較弱。 不容易調試。

20. 如何解決跨域問題?

先了解一下什麼是同源策略

同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,若是缺乏了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協議+域名+端口"三者相同,即使兩個不一樣的域名指向同一個ip地址,也非同源。

同源策略限制如下幾種行爲:

  • Cookie、LocalStorage 和 IndexDB 沒法讀取
  • DOM 和 Js對象沒法得到
  • AJAX 請求不能發送

經常使用跨域解決方案

  • 經過jsonp跨域
  • 跨域資源共享(CORS)
  • nginx代理跨域
  • nodejs中間件代理跨域

(PS:篇幅有限,具體用法自行百度)

21. 說說 event loop

  • ⾸先, js 是單線程的,主要的任務是處理⽤戶的交互,⽽⽤戶的交互⽆⾮就是響應 DOM 的增刪改,使⽤事件隊列的形式,⼀次事件循環只處理⼀個事件
  • 響應,使得腳本執⾏相對連續,因此有了事件隊列,⽤來儲存待執⾏的事件
  • 那麼事件隊列的事件從哪⾥被 push 進來的呢。那就是另外⼀個線程叫事件觸發線程作的事情了
  • 它的做⽤主要是在定時觸發器線程、異步 HTTP 請求線程 滿⾜特定條件下的回調函數 push 到事件隊列中,等待 js 引擎空閒的時候去 執⾏,固然js引擎執⾏過程當中有優先級之分,⾸先js引擎在⼀次事件循環中, 會先執⾏js線程的主任務,而後會去查找是否有微任務 microtask(promise) ,若是有那就優先執⾏微任務,若是沒有,在去查找 宏任務 macrotask(setTimeout、setInterval) 進⾏執⾏

22. 什麼是單線程,和異步的關係

  • 單線程 - 只有⼀個線程,只能作⼀件事
  • 緣由 - 避免 DOM 渲染的衝突
    • 瀏覽器須要渲染 DOM
    • JS 能夠修改 DOM 結構
    • JS 執⾏的時候,瀏覽器 DOM 渲染會暫停
    • 兩段 JS 也不能同時執⾏(都修改 DOM 就衝突了)
    • webworker ⽀持多線程,可是不能訪問 DOM
  • 解決⽅案 - 異步

23. 是否⽤過 jQuery 的 Deferred

使用jQuery Deferred以下:

總結以下:

  • 沒法改變 JS 異步和單線程的本質
  • 只能從寫法上杜絕 callback 這種形式
  • 它是一種語法糖形式,可是解耦了代碼
  • 很好的體現:開放封閉原則

24. 異步編程的實現⽅式

  • 回調函數
    • 優勢:簡單、容易理解
    • 缺點:不利於維護,代碼耦合⾼
  • 事件監聽(採⽤時間驅動模式,取決於某個事件是否發⽣):
    • 優勢:容易理解,能夠綁定多個事件,每一個事件能夠指定多個回調函數
    • 缺點:事件驅動型,流程不夠清晰
  • 發佈/訂閱(觀察者模式)
    • 相似於事件監聽,可是能夠經過‘消息中⼼ʼ,瞭解如今有多少發佈者,多少訂閱者
  • Promise對象
    • 優勢:能夠利⽤then⽅法,進⾏鏈式寫法;能夠書寫錯誤時的回調函數;
    • 缺點:編寫和理解,相對⽐較難
  • Generator函數
    • 優勢:函數體內外的數據交換、錯誤處理機制
    • 缺點:流程管理不⽅便
  • async函數
    • 優勢:內置執⾏器、更好的語義、更⼴的適⽤性、返回的是Promise、結構清晰。
    • 缺點:錯誤處理機制

25. 說說你對promise的瞭解

  • 依照 Promise/A+ 的定義, Promise 有四種狀態:
  • pending: 初始狀態, ⾮ fulfilled 或 rejected.
  • fulfilled: 成功的操做.
  • rejected: 失敗的操做.
  • settled: Promise 已被 fulfilled 或 rejected ,且不是 pending
  • 另外, fulfilled 與 rejected ⼀起合稱 settled
  • Promise 對象⽤來進⾏延遲( deferred ) 和異步( asynchronous ) 計算

Promise 的構造函數

  • 構造⼀個 Promise ,最基本的⽤法以下:
let promise = new Promise(function(resolve, reject) {
    if (...) { // succeed
        resolve(result);
    } else { // fails
        reject(Error(errMessage));
    } 
   });
複製代碼
  • Promise 實例擁有 then ⽅法(具備 then ⽅法的對象,一般被稱爲 thenable )。 它的使⽤⽅法以下:
promise.then(onFulfilled, onRejected)
複製代碼
  • 接收兩個函數做爲參數,⼀個在 fulfilled 的時候被調⽤,⼀個在 rejected 的時候被 調⽤,接收參數就是 future , onFulfilled 對應 resolve , onRejected 對應 reject

26. 談談你對AMD、CMD的理解

  • CommonJS 是服務器端模塊的規範, Node.js 採⽤了這個規範。 CommonJS 規範加載模 塊是同步的,也就是說,只有加載完成,才能執⾏後⾯的操做。 AMD 規範則是⾮同步加載 模塊,容許指定回調函數
  • AMD 推薦的⻛格經過返回⼀個對象作爲模塊對象, CommonJS 的⻛格經過對 module.exports 或 exports 的屬性賦值來達到暴露模塊對象的⽬的

es6模塊 CommonJS、AMD、CMD

  • CommonJS 的規範中,每一個 JavaScript ⽂件就是⼀個獨⽴的模塊上下⽂( module context ),在這個上下⽂中默認建立的屬性都是私有的。也就是說,在⼀個⽂件定義的 變量(還包括函數和類),都是私有的,對其餘⽂件是不可⻅的。
  • CommonJS 是同步加載模塊,在瀏覽器中會出現堵塞狀況,因此不適⽤
  • AMD 異步,須要定義回調 define ⽅式
  • es6 ⼀個模塊就是⼀個獨⽴的⽂件,該⽂件內部的全部變量,外部⽆法獲取。若是你希 望外部可以讀取模塊內部的某個變量,就必須使⽤ export 關鍵字輸出該變量 es6 還可 以導出類、⽅法,⾃動適⽤嚴格模式

27. eval是作什麼的

  • 它的功能是把對應的字符串解析成 JS 代碼並運⾏
  • 應該避免使⽤ eval ,不安全,⾮常耗性能( 2 次,⼀次解析成 js 語句,⼀次執⾏)
  • 由 JSON 字符串轉換爲JSON對象的時候能夠⽤ eval,var obj =eval('('+ str +')')

28. javascript 代碼中的"use strict";是什麼意思

  • use strict 是⼀種 ECMAscript 5 添加的(嚴格)運⾏模式,這種模式使得 Javascript 在更嚴格的條件下運⾏,使 JS 編碼更加規範化的模式,消除 Javascript 語法的⼀些不合 理、不嚴謹之處,減小⼀些怪異⾏爲

29. js延遲加載的⽅式有哪些

  • defer 和 async 、動態建立 DOM ⽅式(⽤得最多)、按需異步載⼊ js

30. defer和async

  • defer 並⾏加載 js ⽂件,會按照⻚⾯上 script 標籤的順序執⾏
  • async 並⾏加載 js ⽂件,下載完成⽴即執⾏,不會按照⻚⾯上 script 標籤的順序執 ⾏

31. 漸進加強和優雅降級

  • 漸進加強 :針對低版本瀏覽器進⾏構建⻚⾯,保證最基本的功能,而後再針對⾼級瀏覽器 進⾏效果、交互等改進和追加功能達到更好的⽤戶體驗。
  • 優雅降級 :⼀開始就構建完整的功能,而後再針對低版本瀏覽器進⾏兼容

32. 說說嚴格模式的限制

  • 變量必須聲明後再使⽤
  • 函數的參數不能有同名屬性,不然報錯
  • 不能使⽤ with 語句
  • 禁⽌ this 指向全局對象

33. 如何經過JS判斷⼀個數組

  • instanceof ⽅法
    • instanceof 運算符是⽤來測試⼀個對象是否在其原型鏈原型構造函數的屬性
let arr = [];
    arr instanceof Array; // true
複製代碼
  • constructor ⽅法
    • constructor 屬性返回對建立此對象的數組函數的引⽤,就是返回對象相對應的構造 函數
let arr = [];
    arr.constructor == Array; //true
複製代碼
  • 最簡單的⽅法 這種寫法,是 jQuery 正在使⽤的
Object.prototype.toString.call(value) == '[object Array]'
    // 利⽤這個⽅法,能夠寫⼀個返回數據類型的⽅法
    let isType = function (obj) {
    return Object.prototype.toString.call(obj).slice(8,-1); }   
複製代碼
  • ES5 新增⽅法 isArray()
let a = new Array(123);
    let b = new Date();
    console.log(Array.isArray(a)); //true
    console.log(Array.isArray(b)); //false 
複製代碼

34. map與forEach的區別

  • forEach ⽅法,是最基本的⽅法,就是遍歷與循環,默認有3個傳參:分別是遍歷的數組 內容 item 、數組索引 index 、和當前遍歷數組 Array
  • map ⽅法,基本⽤法與 forEach ⼀致,可是不一樣的,它會返回⼀個新的數組,因此在 callback須要有 return 值,若是沒有,會返回 undefined

35. JS 數組和對象的遍歷⽅式,以及⼏種⽅式的⽐較

  • for in 循環
  • for 循環
  • forEach
    • 這⾥的 forEach 回調中兩個參數分別爲 value , index
    • forEach ⽆法遍歷對象 IE不⽀持該⽅法; Firefox 和 chrome ⽀持
    • forEach ⽆法使⽤ break , continue 跳出循環,且使⽤ return 是跳過本次循 環
  • 這兩種⽅法應該⾮經常⻅且使⽤很頻繁。但實際上,這兩種⽅法都存在性能問題
  • 在⽅式⼀中, for-in 須要分析出 array 的每一個屬性,這個操做性能開銷很⼤。⽤在 key 已知的數組上是⾮常不划算的。因此儘可能不要⽤ for-in ,除⾮你不清楚要處理哪 些屬性,例如 JSON 對象這樣的狀況
  • 在⽅式2中,循環每進⾏⼀次,就要檢查⼀下數組⻓度。讀取屬性(數組⻓度)要⽐讀局部 變量慢,尤爲是當 array ⾥存放的都是 DOM 元素,由於每次讀取都會掃描⼀遍⻚⾯上 的選擇器相關元素,速度會⼤⼤下降

36. 數組去重⽅法總結

⽅法⼀、利⽤ES6 Set去重(ES6中最常⽤)

function unique (arr) {
    return Array.from(new Set(arr)) }
    var arr = [1,2,3,4,5,,5,4,3,2,1]
    console.log(unique(arr))
    //[1, 2, 3, 4, 5]
複製代碼

⽅法⼆、利⽤for嵌套for,而後splice去重(ES5中最常⽤)

雙層循環,外層循環元素,內層循環時⽐較值。值相同時,則刪去這個值。

function unique(arr){
        for(var i=0; i<arr.length; i++){
            for(var j=i+1; j<arr.length; j++){
                if(arr[i]==arr[j]){ //第⼀個等同於第⼆個,splice⽅法刪除
                     arr.splice(j,1);
                     j--; 
                } 
            } 
        }
        return arr; 
    }
複製代碼

⽅法3、利⽤indexOf去重

新建⼀個空的結果數組, for 循環原數組,判斷結果數組是否存在當前元 素,若是有相同的值則跳過,不相同則 push 進數組

function unique(arr) {
        if (!Array.isArray(arr)) {
         console.log('type error!')
         return
        }
        var array = [];
        for (var i = 0; i < arr.length; i++) {
            if (array .indexOf(arr[i]) === -1) {
             array .push(arr[i]) 
            } 
        }
         return array; 
    }
複製代碼

⽅法4、利⽤sort()

利⽤ sort() 排序⽅法,而後根據排序後的結果進⾏遍歷及相鄰元素⽐對

function unique(arr) {
        if (!Array.isArray(arr)) {
          console.log('type error!')
          return; 
        }
         arr = arr.sort()
        var arrry= [arr[0]];
        for (var i = 1; i < arr.length; i++) {
            if (arr[i] !== arr[i-1]) {
             arrry.push(arr[i]); } 
        }
        return arrry; 
    }
複製代碼

⽅法5、利⽤對象的屬性不能相同的特色進⾏去重

function unique(arr) {
        if (!Array.isArray(arr)) {
            console.log('type error!')
            return
        }
        var arrry= [];
        var obj = {};
        for (var i = 0; i < arr.length; i++) {
            if (!obj[arr[i]]) {
             arrry.push(arr[i])
             obj[arr[i]] = 1 } else {
             obj[arr[i]]++
            } 
        }
        return arrry; 
    }
複製代碼

⽅法6、利⽤includes

function unique(arr) {
        if (!Array.isArray(arr)) {
             console.log('type error!')
             return
        }
        var array =[];
        for(var i = 0; i < arr.length; i++) {
        if( !array.includes( arr[i]) ) {//includes 檢測數組是否有某個值
            array.push(arr[i]); } 
        }
        return array
    }
複製代碼

⽅法7、利⽤hasOwnProperty

利⽤ hasOwnProperty 判斷是否存在對象屬性

function unique(arr) {
        var obj = {};
        return arr.filter(function(item, index, arr){
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof
        }) 
    }
複製代碼

⽅法⼋、利⽤filter

function unique(arr) {
        return arr.filter(function(item, index, arr) {
        //當前元素,在原始數組中的第⼀個索引==當前索引值,不然返回當前元素
        return arr.indexOf(item, 0) === index; }); 
    }
複製代碼

⽅法9、利⽤遞歸去重

function unique(arr) {
        var array= arr;
        var len = array.length;
        array.sort(function(a,b){ //排序後更加⽅便去重
            return a - b; 
        })
        function loop(index){
            if(index >= 1){
                if(array[index] === array[index-1]){
                 array.splice(index,1); }
                loop(index - 1); //遞歸loop,而後數組去重 
              } 
            }
        loop(len-1);
        return array; 
    }
複製代碼

⽅法⼗、利⽤Map數據結構去重

建立⼀個空 Map 數據結構,遍歷須要去重的數組,把數組的每⼀個元素做爲 key 存到 Map 中。因爲 Map 中不會出現相同的 key 值,因此最終獲得的就 是去重後的結果

function arrayNonRepeatfy(arr) {
        let map = new Map();
        let array = new Array(); // 數組⽤於返回結果
        for (let i = 0; i < arr.length; i++) {
            if(map .has(arr[i])) { // 若是有該key值
                map .set(arr[i], true); 
            } else {
                map .set(arr[i], false); // 若是沒有該key值
                array .push(arr[i]); 
            } 
        }
        return array ; 
    }
複製代碼

⽅法⼗⼀、利⽤reduce+includes

function unique(arr){
        return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cu
    }
複製代碼

⽅法⼗⼆、[...new Set(arr)]

[...new Set(arr)]
    //代碼就是這麼少----(其實,嚴格來講並不算是⼀種,相對於第⼀種⽅法來講只是簡化了代碼)
複製代碼

37. 深淺拷⻉

淺拷⻉

  • Object.assign
  • 或者展開運算符

深拷⻉

  • 能夠經過 JSON.parse(JSON.stringify(object)) 來解決
  • 該⽅法也是有侷限性的
    • 會忽略 undefined
    • 不能序列化函數
    • 不能解決循環引⽤的對象

38. 防抖/節流

防抖和節流本質是不⼀樣的。

  • 防抖 是將屢次執⾏變爲最後⼀次執⾏
  • 節流 是將屢次執⾏變成每隔⼀段時間執⾏

39. 談談變量提高?

  • 這是由於函數和變量提高的緣由
  • 一般提高的解釋是說將聲明的代碼移動到了頂部, 這其實沒有什麼錯誤,便於⼤家理解。
  • 可是更準確的解釋應該是:在⽣成執⾏環境時,會有兩個階段。
    • 第⼀個階段是建立的階段,JS 解釋器會找出須要提高的變量和函 數,而且給他們提早在內存中開闢好空間,函數的話會將整個函數存⼊內存中,變量 只聲明而且賦值爲 undefined
    • 因此在第⼆個階段,也就是代碼執⾏階段,咱們可 以直接提早使⽤
  • 在提高的過程當中,相同的函數會覆蓋上⼀個函數,而且函數優先於變量提高

40. let var const

let

  • 容許你聲明⼀個做⽤域被限制在塊級中的變量、語句或者表達式
  • let綁定不受變量提高的約束,這意味着let聲明不會被提高到當前
  • 該變量處於從塊開始到初始化處理的「暫存死區」

var

  • 聲明變量的做⽤域限制在其聲明位置的上下⽂中,⽽⾮聲明變量老是全局的
  • 因爲變量聲明(以及其餘聲明)老是在任意代碼執⾏以前處理的,因此在代碼中的任意位 置聲明變量老是等效於在代碼開頭聲明

const

  • 聲明建立⼀個值的只讀引⽤ (即指針)
  • 基本數據當值發⽣改變時,那麼其對應的指針也將發⽣改變,故形成 const 申明基本數 據類型時
  • 再將其值改變時,將會形成報錯, 例如 jsconst a = 3 ; a = 5 時 將會報錯
  • 可是若是是複合類型時,若是隻改變複合類型的其中某個 Value 項時, 將仍是正常使⽤

41. 怎麼判斷兩個對象相等?

能夠轉換爲字符串來判斷

JSON.stringify(obj1)==JSON.stringify(obj2);//true or false
複製代碼

42. 談⼀談箭頭函數與普通函數的區別?

  • 函數體內的 this 對象,就是定義時所在的對象,⽽不是使⽤時所在的對象
  • 不能夠看成構造函數,也就是說,不可使⽤ new 命令,不然會拋出⼀個錯誤
  • 不可使⽤ arguments 對象,該對象在函數體內不存在。若是要⽤,能夠⽤ Rest 參數 代替
  • 不可使⽤ yield 命令,所以箭頭函數不能⽤做 Generator 函數

43. 談⼀談你理解的函數式編程

  • 簡單說,"函數式編程"是⼀種"編程範式"(programming paradigm),也就是如何編寫程 序的⽅法論
  • 它具備如下特性:閉包和⾼階函數、惰性計算、遞歸、函數是"第⼀等公⺠"、只⽤"表達式"

44. ⽤過哪些設計模式?

  • ⼯⼚模式:
    • ⼯⼚模式解決了重複實例化的問題,但還有⼀個問題,那就是識別問題,由於根本⽆法
    • 主要好處就是能夠消除對象間的耦合,經過使⽤⼯程⽅法⽽不是 new 關鍵字
  • 構造函數模式
    • 使⽤構造函數的⽅法,即解決了重複實例化的問題,⼜解決了對象識別的問題,該模式 與⼯⼚模式的不一樣之處在於
    • 直接將屬性和⽅法賦值給 this 對象;

Web 相關篇

1. 對web標準、可⽤性、可訪問性的理解

  • 可⽤性(Usability):產品是否容易上⼿,⽤戶可否完成任務,效率如何,以及這過程當中 ⽤戶的主觀感覺可好,是從⽤戶的⻆度來看產品的質量。可⽤性好意味着產品質量⾼,是 企業的核⼼競爭⼒
  • 可訪問性(Accessibility):Web內容對於殘障⽤戶的可閱讀和可理解性
  • 可維護性(Maintainability):⼀般包含兩個層次,⼀是當系統出現問題時,快速定位並解 決問題的成本,成本低則可維護性好。⼆是代碼是否容易被⼈理解,是否容易修改和加強 功能。

2. 說說從輸⼊URL到看到⻚⾯發⽣的全過程,越詳細越好

  • ⾸先瀏覽器主進程接管,開了⼀個下載線程
  • 而後進⾏HTTP請求(DNS查詢、IP尋址等等),中間會有三次捂⼿,等待響應,開始下載 響應報⽂
  • 將下載完的內容轉交給Renderer進程管理
  • Renderer進程開始解析css rule tree和dom tree,這兩個過程是並⾏的,因此⼀般我會把 link標籤放在⻚⾯頂部
  • 解析繪製過程當中,當瀏覽器遇到link標籤或者script、img等標籤,瀏覽器會去下載這些內 容,遇到時候緩存的使⽤緩存,不適⽤緩存的從新下載資源
  • css rule tree和dom tree⽣成完了以後,開始合成render tree,這個時候瀏覽器會進⾏ layout,開始計算每⼀個節點的位置,而後進⾏繪製
  • 繪製結束後,關閉TCP鏈接,過程有四次揮⼿

3.說⼀下瀏覽器的緩存機制

瀏覽器緩存機制有兩種,⼀種爲強緩存,⼀種爲協商緩存

  • 對於強緩存,瀏覽器在第⼀次請求的時候,會直接下載資源,而後緩存在本地,第⼆次請 求的時候,直接使⽤緩存
  • 對於協商緩存,第⼀次請求緩存且保存緩存標識與時間,重複請求向服務器發送緩存標識 和最後緩存時間,服務端進⾏校驗,若是失效則使⽤緩存

協商緩存相關設置

  • Exprires :服務端的響應頭,第⼀次請求的時候,告訴客戶端,該資源何時會過 期。 Exprires 的缺陷是必須保證服務端時間和客戶端時間嚴格同步。
  • Cache-control:max-age :表示該資源多少時間後過時,解決了客戶端和服務端時間必 須同步的問題
  • If-None-Match/ETag :緩存標識,對⽐緩存時使⽤它來標識⼀個緩存,第⼀次請求的時 候,服務端會返回該標識給客戶端,客戶端在第⼆次請求的時候會帶上該標識與服務端進 ⾏對⽐並返回 If-None-Match 標識是否表示匹配
  • Last-modified/If-Modified-Since :第⼀次請求的時候服務端返回 Last-modified 代表請求的資源上次的修改時間,第⼆次請求的時候客戶端帶上請求頭 If-ModifiedSince ,表示資源上次的修改時間,服務端拿到這兩個字段進⾏對⽐

4. HTTP狀態碼及其含義

  • 1XX :信息狀態碼
  • 100 Continue 繼續,⼀般在發送 post 請求時,已發送了 http header 以後服務端
  • 將返回此信息,表示確認,以後發送具體參數信息
  • 2XX :成功狀態碼
  • 200 OK 正常返回信息
  • 201 Created 請求成功而且服務器建立了新的資源
  • 202 Accepted 服務器已接受請求,但還沒有處理
  • 3XX :重定向
  • 301 Moved Permanently 請求的⽹⻚已永久移動到新位置。
  • 302 Found 臨時性重定向。
  • 303 See Other 臨時性重定向,且老是使⽤ GET 請求新的 URI 。
  • 304 Not Modified ⾃從上次請求後,請求的⽹⻚未修改過。
  • 4XX :客戶端錯誤
  • 400 Bad Request 服務器⽆法理解請求的格式,客戶端不該當嘗試再次使⽤相同的內 容發起請求。
  • 401 Unauthorized 請求未受權。
  • 403 Forbidden 禁⽌訪問。
  • 404 Not Found 找不到如何與 URI 相匹配的資源。
  • 5XX: 服務器錯誤
  • 500 Internal Server Error 最常⻅的服務器端錯誤。
  • 503 Service Unavailable 服務器端暫時⽆法處理請求(多是過載或維護)。

5. 介紹⼀下你對瀏覽器內核的理解?

  • 主要分紅兩部分:渲染引擎( layout engineer 或 Rendering Engine )和 JS 引擎
  • 渲染引擎:負責取得⽹⻚的內容( HTML 、 XML 、圖像等等)、整理訊息(例如加⼊ CSS 等),以及計算⽹⻚的顯示⽅式,而後會輸出⾄顯示器或打印機。瀏覽器的內核的不 同對於⽹⻚的語法解釋會有不一樣,因此渲染的效果也不相同。全部⽹⻚瀏覽器、電⼦郵件 客戶端以及其它須要編輯、顯示⽹絡內容的應⽤程序都須要內核
  • JS 引擎則:解析和執⾏ javascript 來實現⽹⻚的動態效果
  • 最開始渲染引擎和 JS 引擎並無區分的很明確,後來JS引擎愈來愈獨⽴,內核就傾向於 只指渲染引擎

6. 請描述⼀下 cookies , sessionStorage 和 localStorage 的區別?

  • cookie 是⽹站爲了標示⽤戶身份⽽儲存在⽤戶本地終端(Client Side)上的數據(一般 通過加密)
  • cookie數據始終在同源的http請求中攜帶(即便不須要),記會在瀏覽器和服務器間來回 傳遞
  • sessionStorage 和 localStorage 不會⾃動把數據發給服務器,僅在本地保存
  • 存儲⼤⼩:
    • cookie 數據⼤⼩不能超過4k
    • sessionStorage 和 localStorage 雖然也有存儲⼤⼩的限制,但⽐ cookie ⼤得 多,能夠達到5M或更⼤
  • 有期時間:
    • localStorage 存儲持久數據,瀏覽器關閉後數據不丟失除⾮主動刪除數據
    • sessionStorage 數據在當前瀏覽器窗⼝關閉後⾃動刪除
    • cookie 設置的 cookie 過時時間以前⼀直有效,即便窗⼝或瀏覽器關閉

7. 爲何利⽤多個域名來存儲⽹站資源會更有效?

  • CDN 緩存更⽅便
  • 突破瀏覽器併發限制
  • 節約 cookie 帶寬
  • 節約主域名的鏈接數,優化⻚⾯響應速度
  • 防⽌沒必要要的安全問題

8. 重繪和迴流(重排)是什麼,如何避免?

  • DOM的變化影響到了元素的⼏何屬性(寬⾼),瀏覽器從新計算元素的⼏何屬性,其餘元素 的⼏何
  • 屬性和位置也會受到影響,瀏覽器須要從新構造渲染樹,這個過程稱爲重排,瀏覽器將受 到影響的部分
  • 從新繪製到屏幕上的過程稱爲重繪。引發重排的緣由有
    • 添加或者刪除可⻅的DOM元素,
    • 元素位置、尺⼨、內容改變,
    • 瀏覽器⻚⾯初始化
    • 瀏覽器窗⼝尺⼨改變,重排⼀定重繪,重繪不⼀定重排

減小重繪和重排的⽅法:

  • 不在佈局信息改變時作 DOM 查詢
  • 使⽤ cssText 或者 className ⼀次性改變屬性
  • 使⽤ fragment
  • 對於屢次重排的元素,如動畫,使⽤絕對定位脫離⽂檔流,讓他的改變不影響到其餘元素

9. 常⻅web安全及防禦原理

  • sql 注⼊原理
    • 就是經過把 SQL 命令插⼊到 Web 表單遞交或輸⼊域名或⻚⾯請求的查詢字符串,最終 達到欺騙服務器執⾏惡意的SQL命令
  • 總的來講有如下⼏點
    • 永遠不要信任⽤戶的輸⼊,要對⽤戶的輸⼊進⾏校驗,能夠經過正則表達式,或限制⻓ 度,對單引號和雙 "-" 進⾏轉換等 永遠不要使⽤動態拼裝SQL,可使⽤參數化的 SQL 或者直接使⽤存儲過程進⾏數據查詢存取
    • 永遠不要使⽤管理員權限的數據庫鏈接,爲每一個應⽤使⽤單獨的權限有限的數據庫鏈接
    • 不要把機密信息明⽂存放,請加密或者 hash 掉密碼和敏感的信息

XSS原理及防範

  • Xss(cross-site scripting) 攻擊指的是攻擊者往 Web ⻚⾯⾥插⼊惡意 html 標籤或 者 javascript 代碼。⽐如:攻擊者在論壇中放⼀個看似安全的連接,騙取⽤戶點擊後, 竊取 cookie 中的⽤戶私密信息;或者攻擊者在論壇中加⼀個惡意表單,當⽤戶提交表單 的時候,卻把信息傳送到攻擊者的服務器中,⽽不是⽤戶本來覺得的信任站點

XSS防範⽅法

  • ⾸先代碼⾥對⽤戶輸⼊的地⽅和變量都須要仔細檢查⻓度和對 」<」,」>」,」;」,」’」 等字符 作過濾;其次任何內容寫到⻚⾯以前都必須加以encode,避免不⼩⼼把 html tag 弄出 來。這⼀個層⾯作好,⾄少能夠堵住超過⼀半的XSS 攻擊

XSS與CSRF有什麼區別嗎?

  • XSS 是獲取信息,不須要提早知道其餘⽤戶⻚⾯的代碼和數據包。 CSRF 是代替⽤戶完成 指定的動做,須要知道其餘⽤戶⻚⾯的代碼和數據包。要完成⼀次 CSRF 攻擊,受害者必 須依次完成兩個步驟
  • 登陸受信任⽹站 A ,並在本地⽣成 Cookie
  • 在不登出 A 的狀況下,訪問危險⽹站 B

CSRF的防護

  • 服務端的 CSRF ⽅式⽅法不少樣,但總的思想都是⼀致的,就是在客戶端⻚⾯增長僞隨機數
  • 經過驗證碼的⽅法

10. WebSocket

因爲 http 存在⼀個明顯的弊端(消息只能有客戶端推送到服務器端,⽽服 務器端不能主動推送到客戶端),致使若是服務器若是有連續的變化,這時只 能使⽤輪詢,⽽輪詢效率太低,並不適合。因而 WebSocket 被髮明出來

相⽐與 http 具備如下有點

  • ⽀持雙向通訊,實時性更強;
  • 能夠發送⽂本,也能夠⼆進制⽂件;
  • 協議標識符是 ws ,加密後是 wss ;
  • 較少的控制開銷。鏈接建立後, ws 客戶端、服務端進⾏數據交換時,協議控制的數據包 頭部較⼩。在不包含頭部的狀況下,服務端到客戶端的包頭只有 2~10 字節(取決於數據 包⻓度),客戶端到服務端的的話,須要加上額外的4字節的掩碼。⽽ HTTP 協議每次通訊 都須要攜帶完整的頭部;
  • ⽀持擴展。ws協議定義了擴展,⽤戶能夠擴展協議,或者實現⾃定義的⼦協議。(⽐如⽀ 持⾃定義壓縮算法等)
  • ⽆跨域問題。

11. ajax、axios、fetch區別 jQuery ajax

jQuery ajax

優缺點:

  • 自己是針對 MVC 的編程,不符合如今前端 MVVM 的浪潮
  • 基於原⽣的 XHR 開發, XHR 自己的架構不清晰,已經有了 fetch 的替代⽅案
  • JQuery 整個項⽬太⼤,單純使⽤ ajax 卻要引⼊整個 JQuery ⾮常的不合理(採起個性 化打包的⽅案⼜不能享受CDN服務)

axios 優缺點:

  • 從瀏覽器中建立 XMLHttpRequest
  • 從 node.js 發出 http 請求 ⽀持 Promise API
  • 攔截請求和響應
  • 轉換請求和響應數據
  • 取消請求
  • ⾃動轉換 JSON 數據
  • 客戶端⽀持防⽌ CSRF/XSRF

fetch

優缺點:

  • fetcht 只對⽹絡請求報錯,對 400 , 500 都當作成功的請求,須要封裝去處理
  • fetch 默認不會帶 cookie ,須要添加配置項
  • fetch 不⽀持 abort ,不⽀持超時控制,使⽤ setTimeout 及 Promise.reject 的實 現的超時控制並不能阻⽌請求過程繼續在後臺運⾏,形成了量的浪費
  • fetch 沒有辦法原⽣監測請求的進度,⽽XHR能夠

12. 項⽬作過哪些性能優化?

  • 減小 HTTP 請求數
  • 減小 DNS 查詢
  • 使⽤ CDN
  • 避免重定向
  • 圖⽚懶加載
  • 減小 DOM 元素數量
  • 減小 DOM 操做
  • 使⽤外部 JavaScript 和 CSS
  • 壓縮 JavaScript 、 CSS 、字體、圖⽚等
  • 優化 CSS Sprite
  • 使⽤ iconfont
  • 字體裁剪
  • 多域名分發劃份內容到不一樣域名
  • 儘可能減小 iframe 使⽤
  • 避免圖⽚ src 爲空
  • 把樣式表放在 link 中
  • 把 JavaScript 放在⻚⾯底部

13. 負載均衡

多臺服務器共同協做,不讓其中某⼀臺或⼏臺超額⼯做,發揮服務器的最⼤做 ⽤

  • http 重定向負載均衡:調度者根據策略選擇服務器以302響應請求,缺點只有第⼀次有 效果,後續操做維持在該服務器 dns負載均衡:解析域名時,訪問多個 ip 服務器中的⼀ 個(可監控性較弱)
  • 反向代理負載均衡:訪問統⼀的服務器,由服務器進⾏調度訪問實際的某個服務器,對統 ⼀的服務器要求⼤,性能受到 服務器羣的數量

14. CDN

內容分發⽹絡,基本思路是儘量避開互聯⽹上有可能影響數據傳輸速度和穩 定性的瓶頸和環節,使內容傳輸的更快、更穩定。

15. babel原理

ES六、7 代碼輸⼊ -> babylon 進⾏解析 -> 獲得 AST (抽象語法樹)-> plugin ⽤babel-traverse 對 AST 樹進⾏遍歷轉譯 ->獲得新的 AST 樹-> ⽤ babel-generator 經過 AST 樹⽣成 ES5 代碼

16. 談談你對重構的理解

  • ⽹站重構:在不改變外部⾏爲的前提下,簡化結構、添加可讀性,⽽在⽹站前端保持⼀致 的⾏爲。也就是說是在不改變UI的狀況下,對⽹站進⾏優化, 在擴展的同時保持⼀致的UI
  • 對於傳統的⽹站來講重構一般是:
    • 表格( table )佈局改成 DIV+CSS
    • 使⽹站前端兼容於現代瀏覽器(針對於不合規範的 CSS 、如對IE6有效的)
    • 對於移動平臺的優化
    • 針對於 SEO 進⾏優化

結束篇

若是以爲本文對你修煉有用,能夠點個 star

相關文章
相關標籤/搜索