近期面試題整理

xgod發表於2018-02-01

面試題目,結合網路上的內容參考並總結,會持續更新到找到工作為止,如果有疑問或者錯誤,歡迎提出.

css樣式優先順序:

行內樣式>內聯樣式>外鏈樣

css選擇器工作模式:

從右向左匹配 從左向右匹配看似高效,其實會把前一次匹配後的每一個後代都要遍歷一遍,它的範圍是逐漸變大的,否則就有可能遺漏.而從右向左匹配是先匹配最末端的選擇器,這樣再次匹配的時候只需要去找匹配到的選擇器的父級就可以了,這樣它的範圍是逐漸變小的.

同源策略:

協議,域名和埠都相同時成為一個域,其他域的指令碼無法訪問除了本域意外的內容.這就是同源策略,有了這個策略,網路才相對的安全.同時我們也可以使用一些手段來進行跨域請求,比如:

  1. cors跨域資源共享:通過在請求中新增一個Origin欄位,表示需要跨域請求的地址,如果伺服器端允許這個域訪問,響應頭裡就會有Access-Control-Allow-Origin欄位,表示同意請求.

它分為簡單請求和非簡單請求: 簡單請求:HEAD,GET,POST 並且請求頭裡不超出一下幾種欄位:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

非簡單請求:PUT,DELETE,或者content-typeapplication/json的請求

非簡單請求會先傳送一個試探的請求OPTIONS,同樣請求頭要有Origin,並且加上Access-Control-Request-MethodAccess-Control-Request-Headers,伺服器對試探請求相應成功後響應頭上會有Access-Control-Allow-Origin欄位,接下來的請求就會和簡單請求一樣了.

跨域資源共享的內容參考了阮一峰大大的文章《跨域資源共享 CORS 詳解》

  1. JSONP:利用script標籤的src屬性沒有跨域限制的特點,在需要跨域請求的時候動態生成一個script標籤,src屬性為需要跨域的地址,並且提供一個回撥函式來接受資料,然後伺服器會返回jsonp的包裝,形如callback({...}),然後瀏覽器就會電泳callback回撥函式,並且把解析後的json物件作為引數,然後就可以在這個回撥函式裡處理請求到的資料,只能使用get方法,並且本地的回撥函式需要在全域性作用域下.
  2. window.name
  3. domain
  4. iframe
  • 什麼時候才會有跨域的需求? 前端和後端使用不同的埠時,屬於不同域,不在同源策略之內,這是需要進行跨域相關的配置.

浮點數計算

參考地址:《JavaScript 浮點數運算的精度問題》

0.1+0.2=0.30000000000000004

js中的數字採用的是64位的雙精度浮點數,它的最高位表示符號,接著11位表示指數,餘下的52位為有效數字. 符號位決定的數字的正負,指數部分決定了數值的大小,有效數字部分表示精度

這裡要提一下二進位制如何表示小數.

  • 就比如這個0.1.
  1. 取它的小數部分,當然就是0.1了,乘2得到0.2,這是取它的整數部分第一位表示二進位制小數的第一位(0).
  2. 再乘2,得0.4,取整數部分第一位(0),得到二進位制小數的第二位(0).
  3. 再乘2,得0.8,取整數部分第一位(0).得到二進位制小數的第三位(0).
  4. 再乘2,得1.6,取整數部分第一位(1),得到二進位制小數第四位(1).
  5. 依次類推,會發現,0.1的二進位制小數是這樣的:

0.0001 1001 1001 1001....(無限迴圈)

  • 而0.2的二進位制小數為:

0.0011 0011 0011 0011....(無限迴圈)

而js遵循IEEE754標準的64位雙精度浮點數的小數部分最多隻支援53位二進位制位,所以0.1和0.2的二進位制數相加如下:

0.1 : 0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001

0.2 : 0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011

結果: 0.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100

  • 這裡再將結果轉換成十進位制數:

0+(0 * 2^-1)+(1 * 2^-1)+(0 * 2^-3)+(0 * 2^-4)+(1 * 2^-5)+(1 * 2^-6)+(0 * 2^-7)+(0 * 2^-8)...(總共52位)

最終得到的結果0.30000000000000004,所以在進行算數計算的時候就會產生誤差.

那麼如何消除這種誤差呢?

有效數字最多可以表示53位二進位制數,也就是2^53=9007199254740992,對應的科學計數法為9.007199254740992e+16,這也是js最多能表示的精度,它的小數部分長度為16.

所以我們可以使用toPrecision方法來做精度計算,超過的精度胡自動做湊整處理比如0.30000000000000004.toPrecision(16)=0.3000000000000000,去掉末尾的0後正好是0.3

其實在整數中也同樣存在著精度問題:我們知道js能表示的最大數字(2^53 - 1,Number.MAX_SAFE_INTEGER,9007199254740991)最小數字(-(2^53 - 1),Number.MIN_SAFE_INTEGER,-9007199254740991)

超過了這個範圍的數字的計算就會不準確,但是我們可以通過引入外掛來解決,比如bignumber.js之類的,原理是用過把數字當作字串,重新實現計算的邏輯,缺點就是效能比原生差很多.

toPrecisiontoFixed的區別?

  • toPrecision是處理精度,精度是從左至右第一個不為0的數開始數起.
  • toFixed是小數點後指定位數取整,從小數點開始數起.

遇到浮點數誤差問題時可以直接使用 https://github.com/dt-fe/number-precision 完美支援浮點數的加減乘除、四捨五入等運算。

前端頁面優化

http請求優化

  1. 減少http請求
  • 首先是壓縮,合併js,css檔案,可以配置webpack使其合併成一個唯一的出口檔案.
  • 延遲載入 適合延遲載入的東西很多,最需要的當然是圖片.原理就是首先將要延遲載入的圖片src替換為空白或者指定的loading圖,當達到指定條件的時候再將真是圖片的資源路徑替換到src屬性上讓瀏覽器去載入. 首屏可是使用定時器,其他屏可以通過當前元素的位置,和滾動的距離來判斷是否需要載入圖片
  • 雪碧圖 在容器元素上設定background-image屬性,在子元素上設定background-position屬性來確定其位置
  1. 預載入 延遲載入的目的是為了減少不必要的請求,使用者有需求的時候才去請求資源,而預載入是預先判斷需要載入的資料,預先載入,並且在達到指定條件之後直接從瀏覽器快取中獲取
  2. 靜態資源使用單獨的域名和伺服器 將靜態資源放在額外的伺服器上和域名上,這樣主域名就可以減少http請求數,減少主伺服器的頻寬使用,主伺服器就可以更快的響應請求.
  3. http快取 http快取策略可以把未過期或者未更改的資源重複使用,同樣也可以減少伺服器的頻寬使用.
  4. ajax區域性載入 在達到某些條件後,可以使用ajax重新整理區域性頁面,這樣也可以減少不必要的請求.

頁面/效能優化

  1. 引用優化

將css檔案放在html文件的head標籤內,將js檔案放在body標籤的最下面.

css檔案時非同步載入的,瀏覽器構建dom樹的同時如果有對應的css樣式就是直接渲染出來,這樣會讓樣式更早的呈現在頁面上.

而js檔案下載的時候會阻塞dom數的構建,只有js下載完成後才會繼續構建接下來的dom樹,將js檔案放在最下面可以在視覺上減少白屏的現象.

  1. 將js動畫替換成css動畫

主流瀏覽器已經全部支援的css3

在js中使用動畫是利用定時器迴圈改變dom元素的位置來達到動畫效果,這樣會造成瀏覽器的迴流,會影響前端頁面的效能,如果一定要使用js實現動畫,可以在動畫之前使其脫離正常文件流,在動畫結束之後再讓其迴歸文件流.

而使用css3動畫後,在效能上,瀏覽器會新建一個圖層來執行動畫,並且可以使用硬體加速.在效果上js動畫的最小移動單位為1px,而css3動畫可以打破這個束縛,讓動畫看起來更加流暢.

http快取策略

http快取是減少http請求,減少請求頻寬,增加頁面訪問速度的有效辦法.

http快取主要依靠http報文中的欄位來判斷是都對資料進行快取.

  • 首先是強快取:
  1. 通過cache-control設定max-age=[秒]來設定一個資源的最大儲存事件,他是一個相對事件,意思是存請求成功之後的n秒之內,瀏覽器都直接從本地獲取已快取的資源.

  2. expires:伺服器通過設定expires響應頭,值為一個格林尼治時間,屬於絕對時間,可以告訴瀏覽器快取過氣的時間,在這個過氣事件之前,再次請求的資料都來自本地,在這個時刻之後才會向伺服器請求資源.

expires有一個漏洞,就是他設定的過期事件是需要和本地作業系統的時間進行對比的,如果更改了本地的時間,那麼這個對比就會不準確,而max-age則不會出現這樣的問題,通常為了相容http1.0會將expires和max-age同時設定,在同時設定後,瀏覽器會優先匹配max-age的規則.

  • 協商快取
  1. last-modified:伺服器在第一次接收到請求的時候,可以設定一個last-modified欄位,用來儲存這個資源的最後更改日期,瀏覽器接收到響應後,再次請求的時候,會自動在請求頭中新增if-modified-since欄位,它的值就是第一次響應時的last-modified的值,然後後臺通過判斷這個值與檔案最後修改時間是否相同,如果相同,則可以返回304狀態碼提示瀏覽器使用快取中的資料,如果不同則重新設定last-modified的時間,並返回最新資料.

  2. ETag:伺服器在相應請求的時候通過某種演算法,給資源計算出一個唯一的識別符號,在相應請求的時候會帶上這個識別符號,放在ETag欄位上,而瀏覽器在下次請求的時候會自動帶上一個If-None-Match欄位,值就是第一次請求時的ETag欄位的值,伺服器通過鼻尖請求頭中If-None-Match的值和伺服器上資源的ETag值,如果匹配則返回304狀態碼,提示瀏覽器直接使用本地快取,如果不匹配則重新下載資源.

在以幾個欄位同時設定的情況下,會先使強快取策略生效,如果強快取過期了,才會使用協商快取策略,而如果協商快取策略也同時失效,才會重新下載資源.

  • 還有一個問題如果強快取和協商快取都未失效,而我們又想讓瀏覽器更新資源,這是該怎麼做?

可以通過設定url上的querystring來解決,一般有兩種解決方式:

  1. 使用版本號,比如http://url.com?version=20180201
  2. 使用hash值,比如http://url.com/?hash=sdfkljlkjasdklxclkv13

這樣瀏覽器就會從伺服器更新資源.

原型鏈

  • 原型基礎知識:
  1. 每個建構函式上都有個prototype屬性 ,prototype是一個物件
  2. prototype物件上有一個constructor屬性,這個屬性指向當前的建構函式
  3. 每個物件上都有一個__proto__屬性,這個屬性指向所屬類的原型
  • 屬性和方法查詢順序
  1. 若已找到私有的屬性和方法,則不會再向原型上繼續查詢
  2. 若未找到私有屬性和方法,則通過__proto__去當前例項所屬類的原型上查詢
  3. 若還未找到,則繼續通過__proto__繼續往上級(父類)查詢,直到找到Object類的原型上

若都沒有找到,則返回undefined(查詢物件的屬性和方法,如果沒有這個方法返回的是undefined,不是報錯) Object類是所有型別的基類,其他類為Object的派生類

  • 原型鏈
  1. 通過__proto__屬性一級一級的往父類上查詢,就形成了一個原型鏈 __proto__屬性是實現原型繼承的關鍵

ie中因安全考慮 禁止手動操作__proto__屬性

繼承

  1. 原型鏈繼承:直接讓子類的prototype屬性指向父類的例項,這樣在子類的原型上擁有了父類的私有和公有屬性.
  2. 借用建構函式(經典繼承):在子類的建構函式中使用父類.call(this)方法,在構造新的子類例項的時候其實也執行了父類的初始化程式碼,並且改變了this指向,這樣子類就可以使用父類的私有屬性了
  3. 原型式繼承Object.create():create函式內部建立了一個臨時的中間類,讓這個類的原型等於傳進來的原型物件,最後返回了這個中間類的例項,讓子類的prototype屬性等於返回的例項,這樣就拿到了父類的公有方法.

作用域鏈

  • 全域性作用域:瀏覽器加在頁面時形成,誰都可以訪問,全域性下定義的變數是全域性變數
  • 私有作用域:函式執行時形成,只有自己可以訪問,私有變數:帶var關鍵詞和形參

變數的查詢: 1.先看是否是私有的,如果是私有的(帶var或形參)則就是它 2.如果不是私有的則往上級作用域查詢,如果還沒找到則繼續往上級作用域查詢,直到找到window下,

  • 通過函式形成的作用域一級一級的向上查詢,就形成了作用域鏈

若window下也沒有則會報錯 Uncaught ReferenceError: xxx is not defined

上級作用域:在哪定義的,上級作用域就是誰

專案中大量的靜態資源如何處理

  1. 靜態資源如js,css儘可能合併,圖片合成單張雪碧圖,減少http請求次數.
  2. 使用單獨的域名和伺服器來儲存靜態資源,並設定快取策略,這樣主伺服器可以只接受業務請求,可以有效分流,主伺服器可以更快的相應.
  3. 直接使用CDN服務,將靜態資源儲存在cdn伺服器中,不同地區的使用者訪問網站時,cdn伺服器會查詢最近的擁有靜態資源的伺服器並返回資源,達到訪問加速的目的,並且cdn伺服器也很安全,可以有效防止攻擊.

相關文章