面試題目,結合網路上的內容參考並總結,會持續更新到找到工作為止,如果有疑問或者錯誤,歡迎提出.
css樣式優先順序:
行內樣式>內聯樣式>外鏈樣
css選擇器工作模式:
從右向左匹配 從左向右匹配看似高效,其實會把前一次匹配後的每一個後代都要遍歷一遍,它的範圍是逐漸變大的,否則就有可能遺漏.而從右向左匹配是先匹配最末端的選擇器,這樣再次匹配的時候只需要去找匹配到的選擇器的父級就可以了,這樣它的範圍是逐漸變小的.
同源策略:
協議,域名和埠都相同時成為一個域,其他域的指令碼無法訪問除了本域意外的內容.這就是同源策略,有了這個策略,網路才相對的安全.同時我們也可以使用一些手段來進行跨域請求,比如:
- 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-type
是application/json
的請求
非簡單請求會先傳送一個試探的請求OPTIONS
,同樣請求頭要有Origin
,並且加上Access-Control-Request-Method
和Access-Control-Request-Headers
,伺服器對試探請求相應成功後響應頭上會有Access-Control-Allow-Origin
欄位,接下來的請求就會和簡單請求一樣了.
跨域資源共享的內容參考了阮一峰大大的文章《跨域資源共享 CORS 詳解》
- JSONP:利用script標籤的src屬性沒有跨域限制的特點,在需要跨域請求的時候動態生成一個script標籤,src屬性為需要跨域的地址,並且提供一個回撥函式來接受資料,然後伺服器會返回jsonp的包裝,形如callback({...}),然後瀏覽器就會電泳callback回撥函式,並且把解析後的json物件作為引數,然後就可以在這個回撥函式裡處理請求到的資料,只能使用get方法,並且本地的回撥函式需要在全域性作用域下.
- window.name
- domain
- iframe
- 什麼時候才會有跨域的需求? 前端和後端使用不同的埠時,屬於不同域,不在同源策略之內,這是需要進行跨域相關的配置.
浮點數計算
0.1+0.2=0.30000000000000004
js中的數字採用的是64位的雙精度浮點數,它的最高位表示符號,接著11位表示指數,餘下的52位為有效數字. 符號位決定的數字的正負,指數部分決定了數值的大小,有效數字部分表示精度
這裡要提一下二進位制如何表示小數.
- 就比如這個0.1.
- 取它的小數部分,當然就是0.1了,乘2得到0.2,這是取它的整數部分第一位表示二進位制小數的第一位(0).
- 再乘2,得0.4,取整數部分第一位(0),得到二進位制小數的第二位(0).
- 再乘2,得0.8,取整數部分第一位(0).得到二進位制小數的第三位(0).
- 再乘2,得1.6,取整數部分第一位(1),得到二進位制小數第四位(1).
- 依次類推,會發現,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之類的,原理是用過把數字當作字串,重新實現計算的邏輯,缺點就是效能比原生差很多.
toPrecision
和toFixed
的區別?
toPrecision
是處理精度,精度是從左至右第一個不為0的數開始數起.toFixed
是小數點後指定位數取整,從小數點開始數起.
遇到浮點數誤差問題時可以直接使用
https://github.com/dt-fe/number-precision
完美支援浮點數的加減乘除、四捨五入等運算。
前端頁面優化
http請求優化
- 減少http請求
- 首先是壓縮,合併js,css檔案,可以配置webpack使其合併成一個唯一的出口檔案.
- 延遲載入 適合延遲載入的東西很多,最需要的當然是圖片.原理就是首先將要延遲載入的圖片src替換為空白或者指定的loading圖,當達到指定條件的時候再將真是圖片的資源路徑替換到src屬性上讓瀏覽器去載入. 首屏可是使用定時器,其他屏可以通過當前元素的位置,和滾動的距離來判斷是否需要載入圖片
- 雪碧圖
在容器元素上設定
background-image
屬性,在子元素上設定background-position
屬性來確定其位置
- 預載入 延遲載入的目的是為了減少不必要的請求,使用者有需求的時候才去請求資源,而預載入是預先判斷需要載入的資料,預先載入,並且在達到指定條件之後直接從瀏覽器快取中獲取
- 靜態資源使用單獨的域名和伺服器 將靜態資源放在額外的伺服器上和域名上,這樣主域名就可以減少http請求數,減少主伺服器的頻寬使用,主伺服器就可以更快的響應請求.
- http快取 http快取策略可以把未過期或者未更改的資源重複使用,同樣也可以減少伺服器的頻寬使用.
- ajax區域性載入 在達到某些條件後,可以使用ajax重新整理區域性頁面,這樣也可以減少不必要的請求.
頁面/效能優化
- 引用優化
將css檔案放在html文件的head標籤內,將js檔案放在body標籤的最下面.
css檔案時非同步載入的,瀏覽器構建dom樹的同時如果有對應的css樣式就是直接渲染出來,這樣會讓樣式更早的呈現在頁面上.
而js檔案下載的時候會阻塞dom數的構建,只有js下載完成後才會繼續構建接下來的dom樹,將js檔案放在最下面可以在視覺上減少白屏的現象.
- 將js動畫替換成css動畫
主流瀏覽器已經全部支援的css3
在js中使用動畫是利用定時器迴圈改變dom元素的位置來達到動畫效果,這樣會造成瀏覽器的迴流,會影響前端頁面的效能,如果一定要使用js實現動畫,可以在動畫之前使其脫離正常文件流,在動畫結束之後再讓其迴歸文件流.
而使用css3動畫後,在效能上,瀏覽器會新建一個圖層來執行動畫,並且可以使用硬體加速.在效果上js動畫的最小移動單位為1px,而css3動畫可以打破這個束縛,讓動畫看起來更加流暢.
http快取策略
http快取是減少http請求,減少請求頻寬,增加頁面訪問速度的有效辦法.
http快取主要依靠http報文中的欄位來判斷是都對資料進行快取.
- 首先是強快取:
-
通過cache-control設定max-age=[秒]來設定一個資源的最大儲存事件,他是一個相對事件,意思是存請求成功之後的n秒之內,瀏覽器都直接從本地獲取已快取的資源.
-
expires:伺服器通過設定expires響應頭,值為一個格林尼治時間,屬於絕對時間,可以告訴瀏覽器快取過氣的時間,在這個過氣事件之前,再次請求的資料都來自本地,在這個時刻之後才會向伺服器請求資源.
expires有一個漏洞,就是他設定的過期事件是需要和本地作業系統的時間進行對比的,如果更改了本地的時間,那麼這個對比就會不準確,而max-age則不會出現這樣的問題,通常為了相容http1.0會將expires和max-age同時設定,在同時設定後,瀏覽器會優先匹配max-age的規則.
- 協商快取
-
last-modified:伺服器在第一次接收到請求的時候,可以設定一個last-modified欄位,用來儲存這個資源的最後更改日期,瀏覽器接收到響應後,再次請求的時候,會自動在請求頭中新增if-modified-since欄位,它的值就是第一次響應時的last-modified的值,然後後臺通過判斷這個值與檔案最後修改時間是否相同,如果相同,則可以返回304狀態碼提示瀏覽器使用快取中的資料,如果不同則重新設定last-modified的時間,並返回最新資料.
-
ETag:伺服器在相應請求的時候通過某種演算法,給資源計算出一個唯一的識別符號,在相應請求的時候會帶上這個識別符號,放在ETag欄位上,而瀏覽器在下次請求的時候會自動帶上一個If-None-Match欄位,值就是第一次請求時的ETag欄位的值,伺服器通過鼻尖請求頭中If-None-Match的值和伺服器上資源的ETag值,如果匹配則返回304狀態碼,提示瀏覽器直接使用本地快取,如果不匹配則重新下載資源.
在以幾個欄位同時設定的情況下,會先使強快取策略生效,如果強快取過期了,才會使用協商快取策略,而如果協商快取策略也同時失效,才會重新下載資源.
- 還有一個問題如果強快取和協商快取都未失效,而我們又想讓瀏覽器更新資源,這是該怎麼做?
可以通過設定url上的querystring來解決,一般有兩種解決方式:
- 使用版本號,比如http://url.com?version=20180201
- 使用hash值,比如http://url.com/?hash=sdfkljlkjasdklxclkv13
這樣瀏覽器就會從伺服器更新資源.
原型鏈
- 原型基礎知識:
- 每個建構函式上都有個
prototype
屬性 ,prototype
是一個物件 - prototype物件上有一個
constructor
屬性,這個屬性指向當前的建構函式 - 每個物件上都有一個
__proto__
屬性,這個屬性指向所屬類的原型
- 屬性和方法查詢順序
- 若已找到私有的屬性和方法,則不會再向原型上繼續查詢
- 若未找到私有屬性和方法,則通過
__proto__
去當前例項所屬類的原型上查詢 - 若還未找到,則繼續通過
__proto__
繼續往上級(父類)查詢,直到找到Object
類的原型上
若都沒有找到,則返回
undefined
(查詢物件的屬性和方法,如果沒有這個方法返回的是undefined,不是報錯) Object類是所有型別的基類,其他類為Object的派生類
- 原型鏈
- 通過
__proto__
屬性一級一級的往父類上查詢,就形成了一個原型鏈__proto__
屬性是實現原型繼承的關鍵
ie中因安全考慮 禁止手動操作
__proto__
屬性
繼承
- 原型鏈繼承:直接讓子類的prototype屬性指向父類的例項,這樣在子類的原型上擁有了父類的私有和公有屬性.
- 借用建構函式(經典繼承):在子類的建構函式中使用父類.call(this)方法,在構造新的子類例項的時候其實也執行了父類的初始化程式碼,並且改變了this指向,這樣子類就可以使用父類的私有屬性了
- 原型式繼承Object.create():create函式內部建立了一個臨時的中間類,讓這個類的原型等於傳進來的原型物件,最後返回了這個中間類的例項,讓子類的prototype屬性等於返回的例項,這樣就拿到了父類的公有方法.
作用域鏈
全域性作用域
:瀏覽器加在頁面時形成,誰都可以訪問,全域性下定義的變數是全域性變數私有作用域
:函式執行時形成,只有自己可以訪問,私有變數:帶var關鍵詞和形參
變數的查詢: 1.先看是否是私有的,如果是私有的(帶var或形參)則就是它 2.如果不是私有的則往上級作用域查詢,如果還沒找到則繼續往上級作用域查詢,直到找到window下,
- 通過函式形成的作用域一級一級的向上查詢,就形成了
作用域鏈
。
若window下也沒有則會報錯 Uncaught ReferenceError: xxx is not defined
上級作用域:在哪定義的,上級作用域就是誰
專案中大量的靜態資源如何處理
- 靜態資源如js,css儘可能合併,圖片合成單張雪碧圖,減少http請求次數.
- 使用單獨的域名和伺服器來儲存靜態資源,並設定快取策略,這樣主伺服器可以只接受業務請求,可以有效分流,主伺服器可以更快的相應.
- 直接使用CDN服務,將靜態資源儲存在cdn伺服器中,不同地區的使用者訪問網站時,cdn伺服器會查詢最近的擁有靜態資源的伺服器並返回資源,達到訪問加速的目的,並且cdn伺服器也很安全,可以有效防止攻擊.