深圳地區近期面試100多道題彙總(含超詳細答案)

frontend_frank發表於2020-05-21

前言

你盼世界,我盼望你無bug。Hello 大家好!我是霖呆呆!

哈哈????,這是一篇面試總結文章,抱歉,webpackHTTP系列的先暫緩一下更新哈,Sorry~

這篇文章是呆呆自己近期的一些面試彙總,算了一下有128道,基本都寫了比較完善的答案,就算沒有寫也有推薦一些好的文章連結,文章篇幅較大,整理總結也花費了很多的時間和心血,題目也是根據公司規模的大小從易到難,算是見證了呆呆面試過程中的不足與成長吧 ????。還希望能幫助到正在一起努力求生存的小夥伴們。

"風浪沒平息 我宣告奔跑的意義"

"這不是叛逆 我只是淋了一場雨"

所有文章內容都已整理至 https://github.com/LinDaiDai/niubility-coding-js 快來給我Star呀????~

(因為近期面的主要都是一些深圳的中小公司,他們也還在招聘中,所以不便透露公司名稱,還請大家理解...)

深圳某做海外加速器公司

4月22日上午

1. DIV+CSS佈局的好處

  1. 程式碼精簡,且結構與樣式分離,易於維護

  2. 程式碼量減少了,減少了大量的頻寬,頁面載入的也更快,提升了使用者的體驗

  3. 對SEO搜尋引擎更加友好,且H5又新增了許多語義化標籤更是如此

  4. 允許更多炫酷的頁面效果,豐富了頁面

  5. 符合W3C標準,保證網站不會因為網路應用的升級而被淘汰

缺點: 不同瀏覽器對web標準預設值不同,所以更容易出現對瀏覽器的相容性問題。

2. 如何解決a標點選後hover事件失效的問題?

改變a標籤css屬性的排列順序

只需要記住LoVe HAte原則就可以了:

link→visited→hover→active

比如下面錯誤的程式碼順序:

a:hover{
  color: green;
  text-decoration: none;
}
a:visited{ /* visited在hover後面,這樣的話hover事件就失效了 */
  color: red;
  text-decoration: none;
}

正確的做法是將兩個事件的位置調整一下。

注意⚠️各個階段的含義:

a:link:未訪問時的樣式,一般省略成aa:visited:已經訪問後的樣式a:hover:滑鼠移上去時的樣式a:active:滑鼠按下時的樣式

3. 點選一個input依次觸發的事件

const text = document.getElementById('text');
text.onclick = function (e) {
  console.log('onclick')
}
text.onfocus = function (e) {
  console.log('onfocus')
}
text.onmousedown = function (e) {
  console.log('onmousedown')
}
text.onmouseenter = function (e) {
  console.log('onmouseenter')
}

答案:

'onmouseenter'
'onmousedown'
'onfocus'
'onclick'

4. 響應式的好處

對某些資料的修改就能自動更新檢視,讓開發者不用再去操作DOM,有更多的時間去思考業務邏輯。

5. Vue的優點及缺點

首先Vue最核心的兩個特點,「響應式」「元件化」

「響應式」:這也就是vue.js最大的優點,通過MVVM思想實現資料的雙向繫結,通過虛擬DOM讓我們可以用資料來操作DOM,而不必去操作真實的DOM,提升了效能。且讓開發者有更多的時間去思考業務邏輯。

「元件化」:把一個單頁應用中的各個模組拆分到一個個元件當中,或者把一些公共的部分抽離出來做成一個可複用的元件。所以元件化帶來的好處就是,提高了開發效率,方便重複使用,使專案的可維護性更強。

「虛擬DOM」,當然,這個不是vue中獨有的。

「缺點」:基於物件配置檔案的寫法,也就是options寫法,開發時不利於對一個屬性的查詢。另外一些缺點,在小專案中感覺不太出什麼,vuex的魔法字串,對ts的支援。相容性上存在一些問題。

6. Vue中hash模式和history模式的區別

  • 最明顯的是在顯示上,hash模式的URL中會夾雜著#號,而history沒有。

  • Vue底層對它們的實現方式不同。hash模式是依靠onhashchange事件(監聽location.hash的改變),而history模式是主要是依靠的HTML5 history中新增的兩個方法,pushState()可以改變url地址且不會傳送請求,replaceState()可以讀取歷史記錄棧,還可以對瀏覽器記錄進行修改。

  • 當真正需要通過URL向後端傳送HTTP請求的時候,比如常見的使用者手動輸入URL後回車,或者是重新整理(重啟)瀏覽器,這時候history模式需要後端的支援。因為history模式下,前端的URL必須和實際向後端傳送請求的URL一致,例如有一個URL是帶有路徑path的(例如www.lindaidai.wang/blogs/id),如果後端沒有對這個路徑做處理的話,就會返回404錯誤。所以需要後端增加一個覆蓋所有情況的候選資源,一般會配合前端給出的一個404頁面。

hash:

window.onhashchange = function(event){
  // location.hash獲取到的是包括#號的,如"#heading-3"
  // 所以可以擷取一下
 let hash = location.hash.slice(1);
}

7. react的實現原理?有什麼優缺點?

(技術棧是Vue,沒用過react)

8. react的控制元件和非控制元件

同上

深圳某電商公司

4月22日下午

1. null和undefined的區別

  • null表示一個"無"的物件,也就是該處不應該有值;而undefined表示「未定義」

  • 在轉換為數字時結果不同,Number(null)0,而undefinedNaN

使用場景上:

null

  • 作為函式的引數,表示該函式的引數不是物件

  • 作為物件原型鏈的終點

undefined:

  • 變數被宣告瞭,但沒有賦值時,就等於undefined

  • 呼叫函式時,應該提供的引數沒有提供,該引數等於undefined

  • 物件沒有賦值屬性,該屬性的值為undefined

  • 函式沒有返回值時,預設返回undefined

2. 氣泡排序演算法和陣列去重

「氣泡排序」

function bubbleSort (arr) {
  for (let i = 0; i < arr.length; i++) {
    let flag = true;
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        flag = false;
        let temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
    if (flag) break;
  }
}

這個是優化過後的氣泡排序。用了一個flag來優化,它的意思是:如果「某一次」迴圈中沒有交換過元素,那麼意味著排序已經完成了。

氣泡排序總會執行(N-1)+(N-2)+(N-3)+..+2+1趟,但如果執行到當中某一趟時排序已經完成,或者輸入的是一個有序陣列,那麼後邊的比較就都是多餘的,為了避免這種情況,我們增加一個flag,判斷排序是否在中途就已經完成(也就是判斷有無發生元素交換)

「陣列去重」

  1. Array.form(new Set(arr))

  2. [...new Set(arr)]

  3. for迴圈巢狀,利用splice去重

  4. 新建陣列,利用indexOf或者includes去重

  5. 先用sort排序,然後用一個指標從第0位開始,配合while迴圈去重

當然還有很多,例如用filter、reduce、Map、Object等,具體可以看:

JavaScript陣列去重(12種方法):https://segmentfault.com/a/1190000016418021

Array.form(new Set(arr))[...new Set(arr)]

var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(Array.from(new Set(arr)))
// console.log([...new Set(arr)])

for迴圈巢狀,利用splice去重」

function unique (origin) {
  let arr = [].concat(origin);
  for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] == arr[j]) {
        arr.splice(j, 1);
        j--;
      }
    }
  }
  return arr;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(unique(arr))

「新建陣列,利用indexOf去重」:

function unique (arr) {
  let res = []
  for (let i = 0; i < arr.length; i++) {
    if (!res.includes(arr[i])) {
      res.push(arr[i])
    }
  }
  return res;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(unique(arr))

「先用sort排序,然後用一個指標從第0位開始,配合while迴圈去重」

function unique (arr) {
  arr = arr.sort(); // 排序之後的陣列
  let pointer = 0;
  while (arr[pointer]) {
    if (arr[pointer] != arr[pointer + 1]) { // 若這一項和下一項不相等則指標往下移
      pointer++;
    } else { // 否則刪除下一項
      arr.splice(pointer + 1, 1);
    }
  }
  return arr;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(unique(arr))

深圳某雲產品公司

4月23日上午

(從這家公司開始面試稍微有些難度了,面試官小哥哥人也很好,剛開始是一個高冷男神,但是在呆呆的猛烈回答下終於還是對我露出了微笑????,還說他也是掘友,有看過我的文章...掘友真是無處不在啊,感動????)

1. 描述一下Promise

這道題我會先大概介紹一下Promise

Promise 是一個物件,它代表了一個非同步操作的最終完成或者失敗。由於它的then方法和catch、finally方法會返回一個新的Promise所以可以允許我們鏈式呼叫,解決了傳統的回撥地獄問題。

再說一下then以及catch方法:

(此處我是直接拿我之前的一篇文章《45道Promise題》那裡的總結)

  1. Promise的狀態一經改變就不能再改變。(見3.1)

  2. .then.catch都會返回一個新的Promise。(上面的????1.4證明了)

  3. catch不管被連線到哪裡,都能捕獲上層未捕捉過的錯誤。(見3.2)

  4. Promise中,返回任意一個非 promise 的值都會被包裹成 promise 物件,例如return 2會被包裝為return Promise.resolve(2)

  5. Promise 的 .then 或者 .catch 可以被呼叫多次, 但如果Promise內部的狀態一經改變,並且有了一個值,那麼後續每次呼叫.then或者.catch的時候都會直接拿到該值。(見3.5)

  6. .then 或者 .catch 中 return 一個 error 物件並不會丟擲錯誤,所以不會被後續的 .catch 捕獲。(見3.6)

  7. .then 或 .catch 返回的值不能是 promise 本身,否則會造成死迴圈。(見3.7)

  8. .then 或者 .catch 的引數期望是函式,傳入非函式則會發生值透傳。(見3.8)

  9. .then方法是能接收兩個引數的,第一個是處理成功的函式,第二個是處理失敗的函式,再某些時候你可以認為catch.then第二個引數的簡便寫法。(見3.9)

  10. .finally方法也是返回一個Promise,他在Promise結束的時候,無論結果為resolved還是rejected,都會執行裡面的回撥函式。

另外也可以說一下finally方法:

  1. .finally()方法不管Promise物件最後的狀態如何都會執行

  2. .finally()方法的回撥函式不接受任何的引數,也就是說你在.finally()函式中是沒法知道Promise最終的狀態是resolved還是rejected

  3. 它最終返回的預設會是一個「上一次的Promise物件值」,不過如果丟擲的是一個異常則返回異常的Promise物件。

最後可以說一下all以及race方法:

  • Promise.all()的作用是接收一組非同步任務,然後並行執行非同步任務,並且在所有非同步操作執行完後才執行回撥。

  • .race()的作用也是接收一組非同步任務,然後並行執行非同步任務,只保留取第一個執行完成的非同步操作的結果,其他的方法仍在執行,不過執行結果會被拋棄。

  • Promise.all().then()結果中陣列的順序和Promise.all()接收到的陣列順序一致。

  • all和race傳入的陣列中如果有會丟擲異常的非同步任務,那麼只有最先丟擲的錯誤會被捕獲,並且是被then的第二個引數或者後面的catch捕獲;但並不會影響陣列中其它的非同步任務的執行。

2. Promise.all中如果有一個丟擲異常了會如何處理

這個,在上一題已經說到了:

all和race傳入的陣列中如果有會丟擲異常的非同步任務,那麼只有最先丟擲的錯誤會被捕獲,並且是被then的第二個引數或者後面的catch捕獲;但並不會影響陣列中其它的非同步任務的執行。

3. Promise為什麼能鏈式呼叫

由於它的then方法和catch、finally方法會返回一個新的Promise所以可以允許我們鏈式呼叫

4. 描述一下EventLoop的執行過程

  • 一開始整個指令碼作為一個巨集任務執行

  • 執行過程中同步程式碼直接執行,巨集任務進入巨集任務佇列,微任務進入微任務佇列

  • 當前巨集任務執行完出隊,檢查微任務列表,有則依次執行,直到全部執行完

  • 執行瀏覽器UI執行緒的渲染工作

  • 檢查是否有Web Worker任務,有則執行

  • 執行完本輪的巨集任務,回到2,依此迴圈,直到巨集任務和微任務佇列都為空

(具體可以看這裡:https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-1)

5. docoment,window,html,body的層級關係

「層級關係」

window > document > html > body
  • windowBOM的核心物件,它一方面用來獲取或設定瀏覽器的屬性和行為,另一方面作為一個全域性物件。

  • document物件是一個跟文件相關的物件,擁有一些操作文件內容的功能。但是地位沒有window高。

  • html元素物件和document元素物件是屬於html文件的DOM物件,可以認為就是html原始碼中那些標籤所化成的物件。他們跟div、select什麼物件沒有根本區別。

(我是這樣記的,整個瀏覽器中最大的肯定就是視窗window了,那麼進來的我不管你是啥,就算你是document也得給我盤著)

6. addEventListener函式的第三個引數

第三個引數涉及到冒泡和捕獲,是true時為捕獲,是false則為冒泡

7. 有寫過原生的自定義事件嗎

  • 使用Event

  • 使用customEvent (可以傳引數)

  • 使用document.createEvent('CustomEvent')和initCustomEvent()

「建立自定義事件」

原生自定義事件有三種寫法:

  1. 使用Event

let myEvent = new Event('event_name');
  1. 使用customEvent (可以傳引數)

let myEvent = new CustomEvent('event_name', {
 detail: {
  // 將需要傳遞的引數放到這裡
  // 可以在監聽的回撥函式中獲取到:event.detail
 }
})
  1. 使用document.createEvent('CustomEvent')和initCustomEvent()

let myEvent = document.createEvent('CustomEvent');// 注意這裡是為'CustomEvent'
myEvent.initEvent(
 // 1. event_name: 事件名稱
 // 2. canBubble: 是否冒泡
 // 3. cancelable: 是否可以取消預設行為
)
  • createEvent:建立一個事件

  • initEvent:初始化一個事件

可以看到,initEvent可以指定3個引數。

(有些文章中會說還有第四個引數detail,但是我檢視了W3C上並沒有這個引數,而且實踐了一下也沒有效果)

「事件的監聽」

自定義事件的監聽其實和普通事件的一樣,使用addEventListener來監聽:

button.addEventListener('event_name', function (e) {})

「事件的觸發」

觸發自定義事件使用dispatchEvent(myEvent)

注意⚠️,這裡的引數是要自定義事件的物件(也就是myEvent),而不是自定義事件的名稱('myEvent')

「案例」

來看個案例吧:

// 1.
// let myEvent = new Event('myEvent');
// 2.
// let myEvent = new CustomEvent('myEvent', {
//   detail: {
//     name: 'lindaidai'
//   }
// })
// 3.
let myEvent = document.createEvent('CustomEvent');
myEvent.initEvent('myEvent', true, true)

let btn = document.getElementsByTagName('button')[0]
btn.addEventListener('myEvent', function (e) {
  console.log(e)
  console.log(e.detail)
})
setTimeout(() => {
  btn.dispatchEvent(myEvent)
}, 2000)

8. 冒泡和捕獲的具體過程

冒泡指的是:當給某個目標元素繫結了事件之後,這個事件會依次在它的父級元素中被觸發(當然前提是這個父級元素也有這個同名稱的事件,比如子元素和父元素都繫結了click事件就觸發父元素的click)。

捕獲則是從上層向下層傳遞,與冒泡相反。

(非常好記,你就想想水底有一個泡泡從下面往上傳的,所以是冒泡)

來看看這個例子:

<!-- 會依次執行 button li ul -->
<ul onclick="alert('ul')">
  <li onclick="alert('li')">
    <button onclick="alert('button')">點選</button>
  </li>
</ul>
<script>
  window.addEventListener('click', function (e) {
    alert('window')
  })
  document.addEventListener('click', function (e) {
    alert('document')
  })
</script>

冒泡結果:button > li > ul > document > window

捕獲結果:window > document > ul > li > button

9. 所有的事件都有冒泡嗎?

並不是所有的事件都有冒泡的,例如以下事件就沒有:

  • onblur

  • onfocus

  • onmouseenter

  • onmouseleave

11. 描述下原型鏈

12. 手寫new

function myNew (fn, ...args) {
  let instance = Object.create(fn.prototype);
  let result = fn.call(instance, ...args)
  return typeof result === 'object' ? result : instance;
}

13. typeof和instanceof的區別

typeof表示是對某個變數型別的檢測,基本資料型別除了null都能正常的顯示為對應的型別,引用型別除了函式會顯示為'function',其它都顯示為object

instanceof它主要是「用於檢測某個建構函式的原型物件在不在某個物件的原型鏈上」

14. typeof為什麼對null錯誤的顯示

這只是 JS 存在的一個悠久 Bug。在 JS 的最初版本中使用的是 32 位系統,為了效能考慮使用低位儲存變數的型別資訊,000 開頭代表是物件然而 null 表示為全零,所以將它錯誤的判斷為 object 。

15. 詳細說下instanceof

instanceof它主要是「用於檢測某個建構函式的原型物件在不在某個物件的原型鏈上」

算了,直接手寫實現吧:

function myInstanceof (left, right) {
  let proto = Object.getPrototypeOf(left);
  while (true) {
    if (proto === null) return false;
    if (proto === right.prototype) return true;
    proto = Object.getPrototypeOf(proto)
  }
}

16. 一句話描述一下this

指向最後呼叫函式的那個物件,是函式執行時內部自動生成的一個內部物件,只能在函式內部使用

17. 函式內的this是在什麼時候確定的?

函式呼叫時,指向最後呼叫的那個物件

18. apply/call/bind的相同和不同

19. webpack中的loader和plugin有什麼區別

(答案參考童歐巴的一篇webpack面試文章哦:「吐血整理」再來一打Webpack面試題(持續更新))

loader它是一個轉換器,只專注於轉換檔案這一個領域,完成壓縮、打包、語言編譯,「它僅僅是為了打包」。並且執行在打包之前。

而plugin是一個擴充套件器,它豐富了webpack本身,為其進行一些其它功能的擴充套件。「它不侷限於打包,資源的載入,還有其它的功能」。所以它是在整個編譯週期都起作用。

20. HTTP和TCP的不同

HTTP的責任是去定義資料,在兩臺計算機相互傳遞資訊時,HTTP規定了每段資料以什麼形式表達才是能夠被另外一臺計算機理解。

而TCP所要規定的是資料應該怎麼傳輸才能穩定且高效的傳遞與計算機之間。

(還可以再擴充套件)

21. TCP和UDP的區別

  1. TCP是一個面向連線的、可靠的、基於位元組流的傳輸層協議。

  2. UDP是一個面向無連線的傳輸層協議。

TCP為什麼可靠,是因為它有三次握手來保證雙方都有接受和傳送資料的能力。

位元組流服務:將大塊資料分割為以報文段為單位的資料包進行管理

22. 介紹一下虛擬DOM

虛擬DOM本質就是用一個原生的JavaScript物件去描述一個DOM節點。是對真實DOM的一層抽象。

由於在瀏覽器中操作DOM是很昂貴的。頻繁的操作DOM,會產生一定的效能問題,因此我們需要這一層抽象,在patch過程中儘可能地一次性將差異更新到DOM中,這樣保證了DOM不會出現效能很差的情況。

另外還有很重要的一點,也是它的設計初衷,為了更好的跨平臺,比如Node.js就沒有DOM,如果想實現SSR(服務端渲染),那麼一個方式就是藉助Virtual DOM,因為Virtual DOM本身是JavaScript物件。

Vue2.x中的虛擬DOM主要是借鑑了snabbdom.jsVue3中借鑑inferno.js演算法進行優化。

23. 盒模型

24. 輸入URL到頁面的呈現

看三元的《(1.6w字)瀏覽器靈魂之問,請問你能接得住幾個?》

https://juejin.im/post/5df5bcea6fb9a016091def69

分別從網路,解析,渲染來說

面試的問題基本都答出來了,當然後面還有一個技術總監的電話面,主要是問了一些工作相關的問題。

其實這家公司開出的條件也挺讓呆呆心動的,包括氛圍感覺也挺好,只不過可能還不是自己想要的吧,所以最終也是沒去,挺可惜的...如果面試我的那位小哥哥哥看到了這裡,還請不要難過哈,我們江湖會再見的????。

深圳某房地產公司

4月27日

一面

5道筆試題

並詳細說一下前面三道

(額,呆呆能力有限只答出來了前面三道)

深圳地區近期面試100多道題彙總(含超詳細答案)

二面

1. JSON的原理以及手寫一個實現

基本原理:主要就是利用 script 標籤的src屬性沒有跨域的限制,通過指向一個需要訪問的地址,由服務端返回一個預先定義好的 Javascript 函式的呼叫,並且將伺服器資料以該函式引數的形式傳遞過來,此方法需要前後端配合完成。

執行過程:

  • 前端定義一個解析函式(如: jsonpCallback = function (res) {})

  • 通過params的形式包裝script標籤的請求引數,並且宣告執行函式(如cb=jsonpCallback)

  • 後端獲取到前端宣告的執行函式(jsonpCallback),並以帶上引數且呼叫執行函式的方式傳遞給前端

  • 前端在script標籤返回資源的時候就會去執行jsonpCallback並通過回撥函式的方式拿到資料了。

缺點:

  • 只能進行GET請求

優點:

  • 相容性好,在一些古老的瀏覽器中都可以執行

程式碼實現:

(具體可以看我的這篇文章:JSONP原理及實現:https://www.jianshu.com/p/88bb82718517)

<script>
    function JSONP({
        url,
        params = {},
        callbackKey = 'cb',
        callback
    }) {
        // 定義本地的唯一callbackId,若是沒有的話則初始化為1
        JSONP.callbackId = JSONP.callbackId || 1;
        let callbackId = JSONP.callbackId;
        // 把要執行的回撥加入到JSON物件中,避免汙染window
        JSONP.callbacks = JSONP.callbacks || [];
        JSONP.callbacks[callbackId] = callback;
        // 把這個名稱加入到引數中: 'cb=JSONP.callbacks[1]'
        params[callbackKey] = `JSONP.callbacks[${callbackId}]`;
        // 得到'id=1&cb=JSONP.callbacks[1]'
        const paramString = Object.keys(params).map(key => {
            return `${key}=${encodeURIComponent(params[key])}`
        }).join('&')
        // 建立 script 標籤
        const script = document.createElement('script');
        script.setAttribute('src', `${url}?${paramString}`);
        document.body.appendChild(script);
        // id自增,保證唯一
        JSONP.callbackId++;

    }
    JSONP({
        url: 'http://localhost:8080/api/jsonps',
        params: {
            a: '2&b=3',
            b: '4'
        },
        callbackKey: 'cb',
        callback (res) {
            console.log(res)
        }
    })
    JSONP({
        url: 'http://localhost:8080/api/jsonp',
        params: {
            id: 1
        },
        callbackKey: 'cb',
        callback (res) {
            console.log(res)
        }
    })
</script>

2. 瀏覽器為什麼要跨域?如果是因為安全的話那小程式或者其他的為什麼沒有跨域?

跨域的產生來源於現代瀏覽器所通用的同源策略,所謂同源策略,是指只有在地址的:

  1. 協議名

  2. 域名

  3. 埠名

均一樣的情況下,才允許訪問相同的cookie、localStorage,以及訪問頁面的DOM或是傳送Ajax請求。若在不同源的情況下訪問,就稱為跨域。

例如以下為同源:

http://www.example.com:8080/index.html
http://www.example.com:8080/home.html

以下為跨域:

http://www.example.com:8080/index.html
http://www3.example.com:8080/index.html

注意⚠️:

但是有兩種情況:http預設的埠號為80https預設埠號為443

所以:

http://www.example.com:80 === http://www.example.com
https://www.example.com:443 === https://www.example.com

「為什麼瀏覽器會禁止跨域?」

「簡答」

首先,跨域只存在於瀏覽器端,因為我們知道瀏覽器的形態是很開放的,所以我們需要對它有所限制。

其次,同源策略主要是為了保證使用者資訊的安全,可分為兩種:Ajax同源策略和DOM同源策略。

Ajax同源策略主要是使得不同源的頁面不能獲取cookie且不能發起Ajax請求,這樣在一定程度上防止了CSRF攻擊。

DOM同源策略也一樣,它限制了不同源頁面不能獲取DOM,這樣可以防止一些惡意網站在自己的網站中利用iframe嵌入正規的網站並迷惑使用者,以此來達到竊取使用者資訊。

「深答」

  • 首先,跨域只存在於瀏覽器端。瀏覽器它為web提供了訪問入口,並且訪問的方式很簡單,在位址列輸入要訪問的地址或者點選某個連結就可以了,正是這種「開放的形態」,所以我們需要對它有所限制。

  • 所以同源策略它的產生主要是為了保證使用者資訊的安全,防止惡意的網站竊取資料。分為兩種:Ajax同源策略與DOM同源策略:

    同源策略它算是瀏覽器安全的第一層屏障吧,因為就像CSRF攻擊,它只能限制不同源頁面cookie的獲取,但是攻擊者還可能通過其它的方式來達到攻擊效果。

    (注,上面提到的iframe限制DOM查詢,案例如下)

    // HTML
    <iframe name="yinhang" src="www.yinhang.com"></iframe>
    // JS
    // 由於沒有同源策略的限制,釣魚網站可以直接拿到別的網站的Dom
    const iframe = window.frames['yinhang']
    const node = iframe.document.getElementById('你輸入賬號密碼的Input')
    console.log(`拿到了這個${node},我還拿不到你剛剛輸入的賬號密碼嗎`)
    
    • Ajax同源策略它主要做了這兩種限制:1.不同源頁面不能獲取cookie;2.不同源頁面不能發起Ajax請求。我認為它是防止CSRF攻擊的一種方式吧。因為我們知道cookie這個東西它主要是為了解決瀏覽器與伺服器會話狀態的問題,它本質上是儲存在瀏覽器或本地檔案中一個小小的文字檔案,那麼它裡面一般都會儲存了使用者的一些資訊,包括隱私資訊。如果沒有Ajax同源策略,惡意網站只需要一段指令碼就可以獲取你的cookie,從而冒充你的身份去給其它網站傳送惡意的請求。

    • DOM同源策略也一樣,它限制了不同源頁面不能獲取DOM。例如一個假的網站利用iframe巢狀了一個銀行網站mybank.com,並把寬高或者其它部分調整的和原銀行網站一樣,僅僅只是位址列上的域名不同,若是使用者沒有注意的話就以為這個是個真的網站。如果這時候使用者在裡面輸入了賬號密碼,如果沒有同源策略,那麼這個惡意網站就可以獲取到銀行網站中的DOM,也就能拿到使用者的輸入內容以此來達到竊取使用者資訊的攻擊。

參考:

  • https://segmentfault.com/a/1190000015597029

  • https://juejin.im/post/5cad99796fb9a068ab40a29a

3. CORS跨域的原理

跨域資源共享(CORS)是一種機制,是W3C標準。它允許瀏覽器向跨源伺服器,發出XMLHttpRequestFetch請求。並且整個CORS通訊過程都是瀏覽器自動完成的,不需要使用者參與。

而使用這種跨域資源共享的前提是,瀏覽器必須支援這個功能,並且伺服器端也必須同意這種"跨域"請求。因此實現CORS的關鍵是伺服器需要伺服器。通常是有以下幾個配置:

  • 「Access-Control-Allow-Origin」

  • 「Access-Control-Allow-Methods」

  • 「Access-Control-Allow-Headers」

  • 「Access-Control-Allow-Credentials」

  • 「Access-Control-Max-Age」

具體可看:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

過程分析:

「簡單回答」

  • 當我們發起跨域請求時,「如果是非簡單請求」,瀏覽器會幫我們自動觸發預檢請求,也就是 OPTIONS 請求,用於確認目標資源是否支援跨域。「如果是簡單請求,則不會觸發預檢,直接發出正常請求。」

  • 瀏覽器會根據服務端響應的 header 自動處理剩餘的請求,如果響應支援跨域,則繼續發出正常請求,如果不支援,則在控制檯顯示錯誤。

「詳細回答」

  • 瀏覽器先根據同源策略對前端頁面和後臺互動地址做匹配,若同源,則直接傳送資料請求;若不同源,則傳送跨域請求。

  • 伺服器收到瀏覽器跨域請求後,根據自身配置返回對應檔案頭。若未配置過任何允許跨域,則檔案頭裡不包含 Access-Control-Allow-origin 欄位,若配置過域名,則返回 Access-Control-Allow-origin + 對應配置規則裡的域名的方式

  • 瀏覽器根據接受到的 響應頭裡的 Access-Control-Allow-origin 欄位做匹配,若無該欄位,說明不允許跨域,從而丟擲一個錯誤;若有該欄位,則對欄位內容和當前域名做比對,如果同源,則說明可以跨域,瀏覽器接受該響應;若不同源,則說明該域名不可跨域,瀏覽器不接受該響應,並丟擲一個錯誤。

CORS中有簡單請求非簡單請求,簡單請求是不會觸發CORS的預檢請求的,而非簡單請求會。

“需預檢的請求”要求必須首先使用 OPTIONS  方法發起一個預檢請求到伺服器,以獲知伺服器是否允許該實際請求。"預檢請求“的使用,可以避免跨域請求對伺服器的使用者資料產生未預期的影響。

(關於更多CORS的內容可以看我的另一篇文章:CORS原理及實現:https://www.jianshu.com/p/b2bdf55e1bf5)

4. CORS預請求OPTIONS就一定是安全的嗎?

5. 在深圳的網頁上輸入百度,是怎麼把這個請求發到北京的

這個當時面試官和我說的是,中間會經過很多的站點,比如會經過湖南,或者其它城市,由各個城市的這些站點一層一層分發下去。

6. 輸入URL到頁面的呈現

7. Vue的響應式原理

8. 那在這個響應式中一個資料改變它是怎麼通知要更新的,也就是如何把資料和頁面關聯起來?

面的最慘的一次...因為這次面試是當天下午6點才去面的,在這之前呆呆已經經過了3輪面試的折磨,所以身心疲憊很不在狀態。當然最主要的是自己確實準備的還不夠充分,其實現在回過頭來看看這些題都不太難的...

當天也小小的自閉了一下,整理好狀態第二天好好總結吧 ????。

深圳某海外直播公司

4月28日

(當時是電話面,一個小時20分鐘,問了我大概五六十道題,我能想到的一共是50題,還有一些記不起來了)

1. CommonJS和ES6模組的區別

  • CommonJS模組是執行時載入,ES6 Modules是編譯時輸出介面

  • CommonJS輸出是值的拷貝;ES6 Modules輸出的是值的引用,被輸出模組的內部的改變會影響引用的改變

  • CommonJs匯入的模組路徑可以是一個表示式,因為它使用的是require()方法;而ES6 Modules只能是字串

  • CommonJS this指向當前模組,ES6 Modules this指向undefined

  • 且ES6 Modules中沒有這些頂層變數:argumentsrequiremoduleexports__filename__dirname

關於第一個差異,是因為CommonJS 載入的是一個物件(即module.exports屬性),該物件只有在指令碼執行完才會生成。而 ES6 模組不是物件,它的對外介面只是一種靜態定義,在程式碼靜態解析階段就會生成。

(具體可以看我的這篇文章:https://juejin.im/post/5eaacd175188256d4345ea3a)

2. 模組的非同步載入

模組的非同步載入可以使用AMD或者CMD規範。

(具體可以看我的這篇文章:https://juejin.im/post/5eaacd175188256d4345ea3a)

3. 開發一個模組要考慮哪些問題?

封閉開放式原則、安全性

(應該還有,但是沒想到)

4. 實現一個一組非同步請求按順序執行你有哪些方法?

  1. 利用reduce,初始值傳入一個Promise.resolve(),之後往裡面不停的疊加.then()。(類似於這裡https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-51)

  2. 利用forEach,本質和reduce原理相同。(類似於這裡https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-53)

  3. 還可以用ES9中的for...await...of來實現。

5. Promise.all()是併發的還是序列的?

併發的。不過Promise.all().then()結果中陣列的順序和Promise.all()接收到的陣列順序一致。

6. 平時寫過哪些正規表示式

  • 之前有用過用正則去除輸入框的首尾空格,正規表示式為:var trimReg = /(^\s+)|(\s+$)/g;不過後來由於Vue中有一個修飾符.trim,使用起來更方便(如v-model.trim="msg")就用這種方式多一些;再或者也可以用ES10新出的trimStarttrimEnd來去除首尾空格。

  • 用於校驗手機號的正則:var phoneReg = /^1[3456789]\d{9}$/g

  • 用正則寫一個根據name獲取cookie中的值的方法:

function getCookie(name) {
  var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]*)'));
  if (match) return unescape(match[2]);
}

詳細介紹可以看這裡:每日一題-JS篇-根據name獲取cookie中值的方法:https://github.com/LinDaiDai/niubility-coding-js/blob/master/%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98/%E6%AF%8F%E6%97%A5%E4%B8%80%E9%A2%98-JS%E7%AF%87.md#%E7%94%A8%E6%AD%A3%E5%88%99%E5%86%99%E4%B8%80%E4%B8%AA%E6%A0%B9%E6%8D%AEname%E8%8E%B7%E5%8F%96cookie%E4%B8%AD%E7%9A%84%E5%80%BC%E7%9A%84%E6%96%B9%E6%B3%95

7. 正則裡的非如何實現的

^要是放在[]裡的話就表示"除了^後面的內容都能匹配",也就是非的意思。

例如:

(除了l,其它都變成了"帥")

var str = 'lindaidai';
console.log(str.replace(/[^l]/g, '帥'));
// l帥帥帥帥帥帥帥帥

反之,如果是不在[]裡的話則表示開頭匹配:

(只有l變成了"帥")

var str = 'lindaidai';
console.log(str.replace(/^l/g, '帥'));

8. webpack幾種hash的實現原理

  • hash是跟整個專案的構建相關,只要專案裡有檔案更改,整個專案構建的hash值都會更改,並且全部檔案都共用相同的hash值。(粒度整個專案)

  • chunkhash是根據不同的入口進行依賴檔案解析,構建對應的chunk(模組),生成對應的hash值。只有被修改的chunk(模組)在重新構建之後才會生成新的hash值,不會影響其它的chunk。(粒度entry的每個入口檔案)

  • contenthash是跟每個生成的檔案有關,每個檔案都有一個唯一的hash值。當要構建的檔案內容發生改變時,就會生成新的hash值,且該檔案的改變並不會影響和它同一個模組下的其它檔案。(粒度每個檔案的內容)

(具體可以看我簡書上的這篇文章:https://www.jianshu.com/p/486453d81088)

這裡只是說明了三種hash的不同...至於原理暫時沒了解。

9. webpack如果使用了hash命名,那是每次都會重寫生成hash嗎

這個問題在上一個問題中已經說明了,要看webpack的配置。

有三種情況:

  • 如果是hash的話,是和整個專案有關的,有一處檔案發生更改則所有檔案的hash值都會發生改變且它們共用一個hash值;

  • 如果是chunkhash的話,只和entry的每個入口檔案有關,也就是同一個chunk下的檔案有所改動該chunk下的檔案的hash值就會發生改變

  • 如果是contenthash的話,和每個生成的檔案有關,只有當要構建的檔案內容發生改變時才會給該檔案生成新的hash值,並不會影響其它檔案。

10. webpack中如何處理圖片的?

webpack中有兩種處理圖片的loader

  • file-loader:解決CSS等中引入圖片的路徑問題;(解決通過url,import/require()等引入圖片的問題)

  • url-loader:當圖片小於設定的limit引數值時,url-loader將圖片進行base64編碼(當專案中有很多圖片,通過url-loader進行base64編碼後會減少http請求數量,提高效能),大於limit引數值,則使用file-loader拷貝圖片並輸出到編譯目錄中;

詳細使用可以檢視這裡:霖呆呆的webpack之路-loader篇:https://github.com/LinDaiDai/niubility-coding-js/blob/master/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96/webpack/%E9%9C%96%E5%91%86%E5%91%86%E7%9A%84webpack%E4%B9%8B%E8%B7%AF-loader%E7%AF%87.md#file-loader

11. 說一下回流和重繪

「迴流」

觸發條件:

當我們對 DOM 結構的修改引發 DOM 幾何尺寸變化的時候,會發生迴流的過程。

例如以下操作會觸發迴流:

  1. 一個 DOM 元素的幾何屬性變化,常見的幾何屬性有widthheightpaddingmarginlefttopborder 等等, 這個很好理解。

  2. 使 DOM 節點發生增減或者移動

  3. 讀寫 offset族、scroll族和client族屬性的時候,瀏覽器為了獲取這些值,需要進行迴流操作。

  4. 呼叫 window.getComputedStyle 方法。

迴流過程:由於DOM的結構發生了改變,所以需要從生成DOM這一步開始,重新經過樣式計算生成佈局樹建立圖層樹、再到生成繪製列表以及之後的顯示器顯示這整一個渲染過程走一遍,開銷是非常大的。

「重繪」

觸發條件:

當 DOM 的修改導致了樣式的變化,並且沒有影響幾何屬性的時候,會導致重繪(repaint)。

重繪過程:由於沒有導致 DOM 幾何屬性的變化,因此元素的位置資訊不需要更新,所以當發生重繪的時候,會跳過生存佈局樹建立圖層樹的階段,直接到生成繪製列表,然後繼續進行分塊、生成點陣圖等後面一系列操作。

「如何避免觸發迴流和重繪」

  1. 避免頻繁使用 style,而是採用修改class的方式。

  2. 將動畫效果應用到position屬性為absolutefixed的元素上。

  3. 也可以先為元素設定display: none,操作結束後再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發迴流和重繪

  4. 使用createDocumentFragment進行批量的 DOM 操作。

  5. 對於 resize、scroll 等進行防抖/節流處理。

  6. 避免頻繁讀取會引發迴流/重繪的屬性,如果確實需要多次使用,就用一個變數快取起來。

  7. 利用 CSS3 的transformopacityfilter這些屬性可以實現合成的效果,也就是CPU加速。

參考來源:https://juejin.im/post/5df5bcea6fb9a016091def69#heading-57

12. 盒模型及如何轉換

box-sizing: content-box(W3C盒模型,又名標準盒模型):元素的寬高大小表現為內容的大小。

box-sizing: border-box(IE盒模型,又名怪異盒模型):元素的寬高表現為內容 + 內邊距 + 邊框的大小。背景會延伸到邊框的外沿。

13. 實現水平垂直居中的幾種方式

這裡我是按照子弈的總結答的:https://juejin.im/post/5d690c726fb9a06b155dd40d#heading-81

  • Flex佈局(子元素是塊級元素)

.box {
  display: flex;
  width: 100px;
  height: 100px;
  background-color: pink;
}

.box-center{
  margin: auto;
  background-color: greenyellow;
}
  • Flex佈局

.box {
  display: flex;
  width: 100px;
  height: 100px;
  background-color: pink;
  justify-content: center;
  align-items: center;
}

.box-center{
  background-color: greenyellow;
}
  • 絕對定位實現(定位元素定寬定高)

.box {
  position: relative;
  height: 100px;
  width: 100px;
  background-color: pink;
}

.box-center{
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 0;
  margin: auto;
  width: 50px;
  height: 50px;
  background-color: greenyellow;
}

14. flex的相容性怎樣

「簡單回答:」

IE6~9不支援,IE10~11部分支援flex的2012版,但是需要-ms-字首。

其它的主流瀏覽器包括安卓和IOS基本上都支援了。

「詳細回答:」

  • IE10部分支援2012,需要-ms-字首

  • Android4.1/4.2-4.3部分支援2009 ,需要-webkit-字首

  • Safari7/7.1/8部分支援2012, 需要-webkit-字首

  • IOS Safari7.0-7.1/8.1-8.3部分支援2012,需要-webkit-字首

15. 你知道到哪裡檢視相容性嗎

可以到Can I use上去檢視,官網地址為:https://caniuse.com/

16. 移動端中css你是使用什麼單位

「比較常用的」

  • em:定義字型大小時以父級的字型大小為基準;定義長度單位時以當前字型大小為基準。例父級font-size: 14px,則子級font-size: 1em;font-size: 14px;;若定義長度時,子級的字型大小如果為14px,則子級width: 2em;width: 24px

  • rem:以根元素的字型大小為基準。例如htmlfont-size: 14px,則子級1rem = 14px

  • %:以父級的寬度為基準。例父級width: 200px,則子級width: 50%;height:50%;width: 100px;height: 100px;

  • vw和vh:基於視口的寬度和高度(視口不包括瀏覽器的位址列工具欄和狀態列)。例如視口寬度為1000px,則60vw = 600px;

  • vmin和vmaxvmin為當前vw 和vh中較小的一個值;vmax為較大的一個值。例如視口寬度375px,視口高度812px,則100vmin = 375px;100vmax = 812px;

「不常用的:」

  • ex和chex以字元"x"的高度為基準;例如1ex表示和字元"x"一樣長。ch以數字"0"的寬度為基準;例如2ch表示和2個數字"0"一樣長。

「移動端佈局總結」

  1. 移動端佈局的方式主要使用rem和flex,可以結合各自的優點,比如flex佈局很靈活,但是字型的大小不好控制,我們可以使用rem和媒體查詢控制字型的大小,媒體查詢視口的大小,然後不同的上視口大小下設定設定html的font-size。

  2. 可單獨製作移動端頁面也可響應式pc端移動端共用一個頁面。沒有好壞,視情況而定,因勢利導

(總結來源:玲瓏)

17. rem和em的區別

「em:」

定義字型大小時以父級的字型大小為基準;定義長度單位時以當前字型大小為基準。例父級font-size: 14px,則子級font-size: 1em;font-size: 14px;;若定義長度時,子級的字型大小如果為14px,則子級width: 2em;width: 24px

「rem:」

以根元素的字型大小為基準。例如htmlfont-size: 14px,則子級1rem = 14px

18. 在移動端中怎樣初始化根元素的字型大小

一個簡易版的初始化根元素字型大小。

頁面開頭處引入下面這段程式碼,用於動態計算font-size

(假設你需要的1rem = 20px)

(function () {
  var html = document.documentElement;
  function onWindowResize() {
    html.style.fontSize = html.getBoundingClientRect().width / 20 + 'px';
  }
  window.addEventListener('resize', onWindowResize);
  onWindowResize();
})();
  • document.documentElement:獲取document的根元素

  • html.getBoundingClientRect().width:獲取html的寬度(視窗的寬度)

  • 監聽windowresize事件

一般還需要配合一個meta頭:

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-sacle=1.0, maximum-scale=1.0, user-scalable=no" />

19. 移動端中不同手機html預設的字型大小都是一樣的嗎

如果沒有人為去改變根元素字型大小的話,預設是1rem = 16px;根元素預設的字型大小是16px

20. 你做過哪些動畫效果

實話實說沒太做過。

21. 如果讓你實現一個一直旋轉的動畫你會如何做

css程式碼:

<style>
  .box {
    width: 100px;
    height: 100px;
    background-color: red;
    animation: spin 2s linear infinite;
  }
  @keyframes spin {
    from { transform: rotate(0deg) }
    to { transform: rotate(360deg) }
  }
</style>

html程式碼:

<div class="box"></div>

22. animation介紹一下

語法:

animation: name duration timing-function delay iteration-count direction;
描述
animation-name規定需要繫結到選擇器的 keyframe 名稱。(mymove)
animation-duration規定完成動畫所花費的時間,以秒或毫秒計。(2s)
animation-timing-function規定動畫的速度曲線。(ease|linear|ease-in|cubic-bezier(n,n,n,n))
animation-delay規定在動畫開始之前的延遲。(2s)
animation-iteration-count規定動畫應該播放的次數。(n | infinite) n次/無限
animation-direction規定是否應該輪流反向播放動畫。(normal | alternate) 正常/反向

23. animation有一個steps()功能符知道嗎?

一句話介紹:steps()功能符可以讓動畫不連續。

地位和作用:和貝塞爾曲線(cubic-bezier()修飾符)一樣,都可以作為animation的第三個屬性值。

和貝塞爾曲線的區別:貝塞爾曲線像是滑梯且有4個關鍵字(引數),而steps像是樓梯坡道且只有numberposition兩個關鍵字。

語法:

steps(number, position)
  • number: 數值,表示把動畫分成了多少段

  • position: 表示動畫是從時間段的開頭連續還是末尾連續。支援startend兩個關鍵字,含義分別如下:

    • start:表示直接開始。

    • end:表示戛然而止。是預設值。

具體可以看這裡:https://www.zhangxinxu.com/wordpress/2018/06/css3-animation-steps-step-start-end/

24. 用過哪些移動端的除錯工具

  • Chrome瀏覽器 -> more tools -> Remote devices -> chrome://inspect/#devices

  • Mac + IOS + Safari

25. 說一下原型鏈

26. 詳細說一下instanceof

27. V8的垃圾回收是發生在什麼時候?

V8引擎幫助我們實現了自動的垃圾回收管理,「利用瀏覽器渲染頁面的空閒時間進行垃圾回收。」

28. 具體說一下垃圾回收機制

(這裡我用的是:https://juejin.im/post/5e8b261ae51d4546c0382ab4#heading-20 裡的總結)

「棧記憶體的回收:」

棧記憶體呼叫棧上下文切換後就被回收,比較簡單。

「堆記憶體的回收:」

V8的堆記憶體分為新生代記憶體和老生代記憶體,新生代記憶體是臨時分配的記憶體,存在時間短,老生代記憶體存在時間長。

新生代記憶體回收機制:

  • 新生代記憶體容量小,64位系統下僅有32M。新生代記憶體分為「From、To」兩部分,進行垃圾回收時,先掃描From,將非存活物件回收,將存活物件順序複製到To中,之後調換From/To,等待下一次回收

老生代記憶體回收機制

  • 「晉升」:如果新生代的變數經過多次回收依然存在,那麼就會被放入老生代記憶體中

  • 「標記清除」:老生代記憶體會先遍歷所有物件並打上標記,然後對正在使用或被強引用的物件取消標記,回收被標記的物件

  • 「整理記憶體碎片」:把物件挪到記憶體的一端

(當然想要詳細瞭解的話也可以看我的這篇文章:JavaScript進階-記憶體機制(表情包初探)

29. 在專案中如何把http的請求換成https

由於我在專案中是會對axios做一層封裝,所以每次請求的域名也是寫在配置檔案中,有一個baseURL欄位專門用於儲存它,所以只要改這個欄位就可以達到替換所有請求httphttps了。

當然後面我也有了解到:

利用meta標籤把http請求換為https:

<meta http-equiv ="Content-Security-Policy" content="upgrade-insecure-requests">

30. 知道meta標籤有把http換成https的功能嗎?

參考上一題????。

31. http請求可以怎麼攔截

在瀏覽器和伺服器進行傳輸的時候,可以被nginx代理所攔截,也可以被閘道器攔截。

32. https的加密方式

HTTPS主要是採用對稱金鑰加密和非對稱金鑰加密組合而成的混合加密機制進行傳輸。

也就是傳送密文的一方用"對方的公鑰"進行加密處理"對稱的金鑰",然後對方在收到之後使用自己的私鑰進行解密得到"對稱的金鑰",這在確保雙發交換的金鑰是安全的前提下使用對稱金鑰方式進行通訊。

33. 混合加密的好處

對稱金鑰加密和非對稱金鑰加密都有它們各種的優缺點,而混合加密機制就是將兩者結合利用它們各自的優點來進行加密傳輸。

比如既然對稱金鑰的優點是加解密效率快,那麼在客戶端與服務端確定了連線之後就可以用它來進行加密傳輸。不過前提是得解決雙方都能安全的拿到這把對稱金鑰。這時候就可以利用非對稱金鑰加密來傳輸這把對稱金鑰,因為我們知道非對稱金鑰加密的優點就是能保證傳輸的內容是安全的。

所以它的好處是即保證了對稱金鑰能在雙方之間安全的傳輸,又能使用對稱加密方式進行通訊,這比單純的使用非對稱加密通訊快了很多。以此來解決了HTTP中內容可能被竊聽的問題。

其它HTTP相關的問題:

如:

  • HTTPS的工作流程

  • 混合加密機制的好處

  • 數字簽名

  • ECDHE握手和RSA握手

  • 向前安全性

這些問題都可以看到我的這篇文章:HTTPS面試問答:https://github.com/LinDaiDai/niubility-coding-js/blob/master/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/HTTPS%E9%9D%A2%E8%AF%95%E9%97%AE%E7%AD%94.md

34. 瀏覽器如何驗證伺服器的身份

這道題主要可以從數字簽名數字證照上來答。

當時我答的時候就把證照的頒發流程HTTPS數字證照的驗證過程完整的說了一遍就算過了。

具體可以看「HTTPS面試」????問答中的第5、6、7問。

35. ETag首部欄位說一下

這個無非就是配合If-None-Match來達到一個協商快取的作用。值為伺服器某個資源的唯一標識。

具體可以看我的這篇文章:霖呆呆你來說說瀏覽器快取吧

36. 你們的token一般是存放在哪裡的

Token其實就是「訪問資源的憑證」

一般是使用者通過使用者名稱和密碼登入成功之後,伺服器將登陸憑證做數字簽名,加密之後得到的字串作為token

它在使用者登入成功之後會返回給客戶端,客戶端主要有這麼幾種儲存方式:

  1. 儲存在localStorage中,每次呼叫介面的時候都把它當成一個欄位傳給後臺

  2. 儲存在cookie中,讓它自動傳送,不過缺點就是不能跨域

  3. 拿到之後儲存在localStorage中,每次呼叫介面的時候放在HTTP請求頭的Authorization欄位裡

(很明顯我答的不夠專業,歡迎補充,感謝????)

37. token會不會被偽造?

(很明顯我答的不夠專業,歡迎補充,感謝????)

38. redis中一般用來存什麼

使用者登入成功之後的一些資訊

(很明顯我答的不夠專業,歡迎補充,感謝????)

39. 前後端如何驗證一個使用者是否下線了

(很明顯我答的不夠專業,歡迎補充,感謝????)

40. CSP白名單知道嗎?

(很明顯我答的不夠專業,歡迎補充,感謝????)

41. nginx有配置過嗎?

只會配置一些跨域方面的問題。

events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass  http://localhost:8887;
            add_header  Access-Control-Allow-Origin *;
        }
    }
}

利用ngnix跨域的關鍵就是在配置檔案中設定server項,然後設定其中的location屬性,proxy_pass:需要代理的伺服器地址,add_header:給響應報文中新增首部欄位,例如Access-Control-Allow-Origin設定為*,即允許所有的請求源請求。

具體可以看:Yiming君-面試題:nginx有配置過嗎?反向代理知道嗎?
https://juejin.im/post/5eb0f8aaf265da7ba65f7ba2

42. 反向代理知道嗎?

我們將請求傳送到伺服器,然後伺服器對我們的請求進行轉發,我們只需要和代理伺服器進行通訊就好。所以對於客戶端來說,是感知不到伺服器的。

43. 有用過抓包工具嗎?

唔...沒有...

44. 你平常用的電腦是Mac嗎?

(...在電話那頭默默的點頭)

45. Fiddler有用過嗎?

唔...知道...

46. Vue的diff演算法

這裡我是按照:

https://mp.weixin.qq.com/s/2xyP4jVevuXrGov_VsWfvA

中的第13題答的。

47. Vue中computed和methods的區別

48. 例如要獲取當前時間你會放到computed還是methods裡?

放在methods中,因為computed會有惰性,並不能知道new Date()的改變。

49. 你們的許可權功能是怎麼做的?

小小的寫了一篇文章,可以看這裡:資料許可權如何控制
https://github.com/LinDaiDai/niubility-coding-js/blob/master/other/%E6%95%B0%E6%8D%AE%E6%9D%83%E9%99%90%E5%A6%82%E4%BD%95%E6%8E%A7%E5%88%B6.md

50. 那你在判斷許可權的時候是用的字串匹配還是位運算?

和麵試官扯了一堆我資料許可權判斷的具體過程,其中可能有多個許可權:並的情況000011110001&000011110002,或的情況000011110001|000011110002,以及如何做的許可權匹配。最後面試官:

"所以那還是用的字串匹配咯?"

尬...我比較low...用的字串匹配...

(哇,真的絕了...1個小時20分鐘50多道題,答的我口渴????,不過也可以看出有很多移動端的我都沒有答上來,面試官也表示理解,畢竟我主要是以PC端為主,所以竟然也算是過了,很感謝這位面試官細心的幫我分析一些問題)

後來有了解這位面試官近期也跳槽去騰訊了,果然面完呆呆之後他就去大廠了,好人一生平安????????。

深圳某國內直播公司

這家公司其實是上家公司的總部,因為面完上家之後,HR也知道我的顧慮,想要去一個大點的團隊,所以就把我推薦去了他們的總部。非常Nice的HR小姐姐,好感動,就算你看不到我的文章,我也還是要感謝你 ????。

5月8日

一面(前端副總監)

1. 輸入URL到頁面呈現

(必問...)

看三元的《(1.6w字)瀏覽器靈魂之問,請問你能接得住幾個?》
https://juejin.im/post/5df5bcea6fb9a016091def69

分別從網路,解析,渲染來說

2. 為什麼說script標籤建議放在body下面?

JS程式碼在載入完之後是立即執行的,且JS程式碼執行時會阻塞頁面的渲染。

3. 為什麼說script標籤會阻塞頁面的渲染呢?渲染執行緒和js引擎執行緒不是分開的嗎?

JS屬於單執行緒,當我們在載入script標籤內容的時候,渲染執行緒會被暫停,因為script標籤裡可能會操作DOM的,所以如果你載入script標籤又同時渲染頁面肯定就衝突了,因此說渲染執行緒(GUI)和js引擎執行緒互斥。

4. 協商快取說一下

Last-Modefied配合If-Modified-Since

ETag配合If-None-Match

也是個常見的問題了,不瞭解的小夥伴可以看我的這篇文章:霖呆呆你來說說瀏覽器快取吧

(當時面試官還重複了一下我說的這4個頭部欄位,自己回顧了一下我說的對不對,好可愛~)

5. HTTP中的Keep-Alive有了解過嗎?

Keep-AliveHTTP的一個頭部欄位Connection中的一個值,它是保證我們的HTTP請求能建立一個持久連線。也就是說建立一次TCP連線即可進行多次請求和響應的互動。它的特點就是隻要有一方沒有明確的提出斷開連線,則保持TCP連線狀態,減少了TCP連線和斷開造成的額外開銷。

另外,在HTTP/1.1中所有的連線預設都是持久連線的,但是HTTP/1.0並未標準化。

6. 跨域有了解嗎?如何解決跨域?

我工作中碰到主要是利用CORS來解決跨域問題,說了一下它的原理以及後臺需要如何做。

另外說到了JSONP的原理,以及它的優點:相容性好;缺點:只能進行GET請求,且有安全問題。

還有說到了ngnix反向代理來解決跨域。

  • CORS原理及實現:https://www.jianshu.com/p/b2bdf55e1bf5

  • JSONP原理及實現:https://www.jianshu.com/p/88bb82718517

  • 面試題:nginx有配置過嗎?反向代理知道嗎?:https://juejin.im/post/5eb0f8aaf265da7ba65f7ba2

其它的,我當時說我有看過一篇文章裡面詳細的介紹10多種跨域解決方案,但是自己沒有過多的去了解。

哈哈,其實也就是秋風大大的這篇文章10種跨域解決方案(附終極大招)

7. WebSocket有了解過嗎?它也可以跨域的

這個當時答的沒用過。

我知道它是能使得客戶端和伺服器之間存在持久的連線,而且雙方都可以隨時開始傳送資料,這種方式本質沒有使用 HTTP 的響應頭,因此也沒有跨域的限制。

(多的不會了)

8. 前端安全方面?XSS?CSRF?

(必問...)

(以下回答參考子弈小哥哥的面試分享:兩年工作經驗成功面試阿里P6總結:https://juejin.im/post/5d690c726fb9a06b155dd40d#heading-60

以及蔡徐坤小哥哥的2萬字 | 前端基礎拾遺90問:https://juejin.im/post/5e8b261ae51d4546c0382ab4#heading-48

「XSS」

XSS(Cross Site Script)跨站指令碼攻擊。指的是攻擊者向網頁注入惡意的客戶端程式碼,通過惡意的指令碼對客戶端網頁進行篡改,從而在使用者瀏覽網頁時,對使用者瀏覽器進行控制或者獲取使用者隱私資料的一種攻擊方式。

主要是分為三種:

「儲存型」:即攻擊被儲存在服務端,常見的是在評論區插入攻擊指令碼,如果指令碼被儲存到服務端,那麼所有看見對應評論的使用者都會受到攻擊。

「反射型」:攻擊者將指令碼混在URL裡,服務端接收到URL將惡意程式碼當做引數取出並拼接在HTML裡返回,瀏覽器解析此HTML後即執行惡意程式碼

「DOM型」:將攻擊指令碼寫在URL中,誘導使用者點選該URL,如果URL被解析,那麼攻擊指令碼就會被執行。和前兩者的差別主要在於DOM型攻擊不經過服務端

如何防禦XSS攻擊

  • 「輸入檢查」:對輸入內容中的script<iframe>等標籤進行轉義或者過濾

  • 「設定httpOnly」:很多XSS攻擊目標都是竊取使用者cookie偽造身份認證,設定此屬性可防止JS獲取cookie

  • 「開啟CSP」,即開啟白名單,可阻止白名單以外的資源載入和執行

「CSRF」

CSRF攻擊(Cross-site request forgery)跨站請求偽造。是一種劫持受信任使用者向伺服器傳送非預期請求的攻擊方式,通常情況下,它是攻擊者藉助受害者的 Cookie 騙取伺服器的信任,但是它並不能拿到Cookie,也看不到Cookie的內容,它能做的就是給伺服器傳送請求,然後執行請求中所描述的命令,以此來改變伺服器中的資料,也就是並不能竊取伺服器中的資料。

防禦主要有三種:

驗證Token:瀏覽器請求伺服器時,伺服器返回一個token,每個請求都需要同時帶上token和cookie才會被認為是合法請求

驗證Referer:通過驗證請求頭的Referer來驗證來源站點,但請求頭很容易偽造

設定SameSite:設定cookie的SameSite,可以讓cookie不隨跨站請求發出,但瀏覽器相容不一

「點選挾持」

  • 誘使使用者點選看似無害的按鈕(實則點選了透明 iframe 中的按鈕).

  • 監聽滑鼠移動事件,讓危險按鈕始終在滑鼠下方.

  • 使用 HTML5 拖拽技術執行敏感操作(例如 deploy key).

預防策略:

  1. 服務端新增 X-Frame-Options 響應頭,這個 HTTP 響應頭是為了防禦用 iframe 巢狀的點選劫持攻擊。這樣瀏覽器就會阻止嵌入網頁的渲染。

  2. JS 判斷頂層視口的域名是不是和本頁面的域名一致,不一致則不允許操作,top.location.hostname === self.location.hostname

  3. 敏感操作使用更復雜的步驟(驗證碼、輸入專案名稱以刪除)。

(這個來源於LuckyWinty: http://www.imooc.com/article/295400)

9. setTimeout的執行原理(EventLoop)

(必問...)

(回答參考:https://juejin.im/post/5e621f5fe51d452700567c32)

setTimeout的執行機制:執行該語句時,是立即把當前定時器程式碼推入事件佇列,當定時器在事件列表中滿足設定的時間值時將傳入的函式加入任務佇列,之後的執行就交給任務佇列負責。但是如果此時任務佇列不為空,則需等待,所以執行定時器內程式碼的時間可能會大於設定的時間

說了一下它屬於非同步任務,然後說了一下還有哪些巨集任務以及微任務,最後說了一下EventLoop的執行過程。

  • 一開始整個指令碼作為一個巨集任務執行

  • 執行過程中同步程式碼直接執行,巨集任務進入巨集任務佇列,微任務進入微任務佇列

  • 當前巨集任務執行完出隊,檢查微任務列表,有則依次執行,直到全部執行完

  • 執行瀏覽器UI執行緒的渲染工作

  • 檢查是否有Web Worker任務,有則執行

  • 執行完本輪的巨集任務,回到2,依此迴圈,直到巨集任務和微任務佇列都為空

(具體可以看這裡:https://juejin.im/post/5e58c618e51d4526ed66b5cf#heading-1)

10. requestAnimationFrame有了解過嗎?

(啪啪啪,不長記性,其實之前面試有被問過,但是忘了再去了解了,這就吃虧了,沒答上來)

requestAnimationFrame是瀏覽器用於定時迴圈操作的一個介面,類似於setTimeout,主要用途是按幀對網頁進行重繪。對於JS動畫,用requestAnimationFrame 會比 setInterval 效果更好。

具體可以看:https://juejin.im/post/5e621f5fe51d452700567c32

11. requestAnimationFrame和setTimeout的區別?

同上...

12. 平常工作中ES6+主要用到了哪些?

(下面看著很多,但我肯定不是全答哈,挑了幾個來回答)

ES6

  1. Class

  2. 模組importexport

  3. 箭頭函式

  4. 函式預設引數

  5. ...擴充套件運輸符允許展開陣列

  6. 解構

  7. 字串模版

  8. Promise

  9. let const

  10. Proxy、Map、Set

  11. 物件屬性同名能簡寫

ES7

  1. includes

  2. **求冪運算子

ES8

  1. async/await

  2. Object.values()和Object.entries()

  3. padStart()和padEnd()

  4. Object.getOwnPropertyDescriptors()

  5. 函式引數允許尾部,

ES9

  1. for...await...of

  2. ...展開符合允許展開物件收集剩餘引數

  3. Promise.finally()

  4. 正則中的四個新功能

ES10

  1. flat()

  2. flatMap()

  3. fromEntries()

  4. trimStarttrimEnd

  5. matchAll

  6. BigInt

  7. try/catch中報錯允許沒有err異常引數

  8. Symbol.prototype.description

  9. Function.toString()呼叫時呈現原本原始碼的樣子

還不瞭解的小夥伴可以看看浪裡哥的這篇:盤點ES7、ES8、ES9、ES10新特性

https://juejin.im/post/5dda2b5e6fb9a07a83691766

13. 如何在前端實現一個圖片壓縮

實話實話沒做過,但是後來面試官告訴我:可以使用canvas來實現。具體做法等我寫篇文章哈。

(當時我還反問了一句面試官:那批量圖片壓縮要怎麼做呢?把他驚的...然後他和我說挺複雜的...

16. 專案中有碰到什麼難的問題嗎?如何解決的?

例舉了我最經典的bpmn.js,以此來引出我寫了很多關於這方面的教材,以及建立了微信群,為國內的bpmn.js社群貢獻了一份力量...怎麼高大上怎麼來...

當然也有提到我GitHub上的bpmn-chinese-document專案只有100多的Star,他說理解,畢竟這東西用的人不是很多。

17. 期望薪資多少?

喊了個挺高的數,老哥笑了笑,你這個工作年限我們可能給不到,然後扯了點別的。

18. 還有什麼想要問我的嗎?

  • 團隊人員分佈情況

  • 技術棧

  • 我進去主要是負責哪塊內容

  • 年終獎/季度獎

  • 調薪的頻率以及幅度

  • 加班多不多

(其實後面這些問題應該是等到HR面的時候問的,但是感覺和麵試官挺聊的來的我就先打聽了)

二面(CTO)

1. JSONP的實現原理

絕了...又來

2. XSS攻擊以及如何預防?

絕了...又來X2

3. 不使用框架如何實現元件按需載入以及原理

當時答的是是用import來按需引入,以及提到了Vue.use

但後來有去了解,babel-plugin-import就可以實現。

4. 你們這個是自己寫的元件庫嗎?

估計面試官看錯了...雖然我的專案有個元件庫的功能,但是是基於Ant Design of Vue二次開發的。

面試推薦好文

  • 面試分享:兩年工作經驗成功面試阿里P6總結:https://juejin.im/post/5d690c726fb9a06b155dd40d

  • 2萬字 | 前端基礎拾遺90問:https://juejin.im/post/5e8b261ae51d4546c0382ab4

  • 一位前端小姐姐的五萬字面試寶典https://juejin.im/post/5e91b01651882573716a9b23

  • 藝術喵 2 年前端面試心路歷程(位元組跳動、YY、虎牙、BIGO)| 掘金技術徵文:https://juejin.im/post/5e85ec79e51d4547153d0738

  • 一年半經驗前端社招7家大廠&獨角獸全過經歷 | 掘金技術徵文:https://juejin.im/post/5e8d5a48f265da47ce6cb21f

  • 面試完50個人後我寫下這篇總結:https://juejin.im/post/5df1e312f265da33d039d06d

  • 「吐血整理」再來一打Webpack面試題(持續更新)

  • (1.6w字)瀏覽器靈魂之問,請問你能接得住幾個?: https://juejin.im/post/5df5bcea6fb9a016091def69

(還有很多大佬的很多好文,不是呆呆不寫在這裡啊,是因為呆呆暫時只刷了這些,抱歉了????)

後語

你盼世界,我盼望你無bug。這篇文章就介紹到了這裡。

我是一隻正在努力求生存的呆呆,也在這條路上不斷的總結和成長,希望自己能夠堅持✊。

"風浪沒平息 我宣告奔跑的意義"

"這不是叛逆 我只是淋了一場雨"

喜歡「霖呆呆」的小夥還希望可以關注霖呆呆的公眾號 LinDaiDai 

我會不定時的更新一些前端方面的知識內容以及自己的原創文章????

你的鼓勵就是我持續創作的主要動力 ????.

相關文章