文章轉載:樂位元組
簡答題
1、什麼是防抖和節流?有什麼區別?如何實現?
參考答案
防抖
觸發高頻事件後n秒內函式只會執行一次,如果n秒內高頻事件再次被觸發,則重新計算時間
思路:
每次觸發事件時都取消之前的延時呼叫方法
function debounce(fn) {
let timeout = null; // 建立一個標記用來存放定時器的返回值
return function () {
clearTimeout(timeout); // 每當使用者輸入的時候把前一個 setTimeout clear 掉
timeout = setTimeout(() => { // 然後又建立一個新的 setTimeout, 這樣就能保證輸入字元後的 interval 間隔內如果還有字元輸入的話,就不會執行 fn 函式
fn。apply(this, arguments);
}, 500);
};
}
function sayHi() {
console。log(‘防抖成功’);
}
var inp = document。getElementById(‘inp’);
inp。addEventListener(‘input’, debounce(sayHi)); // 防抖
節流
高頻事件觸發,但在n秒內只會執行一次,所以節流會稀釋函式的執行頻率
思路:
每次觸發事件時都判斷當前是否有等待執行的延時函式
function throttle(fn) {
let canRun = true; // 透過閉包儲存一個標記
return function () {
if (!canRun) return; // 在函式開頭判斷標記是否為true,不為true則return
canRun = false; // 立即設定為false
setTimeout(() => { // 將外部傳入的函式的執行放在setTimeout中
fn。apply(this, arguments);
// 最後在setTimeout執行完畢後再把標記設定為true(關鍵)表示可以執行下一次迴圈了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉
canRun = true;
}, 500);
};
}
function sayHi(e) {
console。log(e。target。innerWidth, e。target。innerHeight);
}
window。addEventListener(‘resize’, throttle(sayHi));
2、 get請求傳參長度的誤區、get和post請求在快取方面的區別
誤區:我們經常說get請求引數的大小存在限制,而post請求的引數大小是無限制的。
參考答案
實際上HTTP 協議從未規定 GET/POST 的請求長度限制是多少。對get請求引數的限制是來源與瀏覽器或web伺服器,瀏覽器或web伺服器限制了url的長度。為了明確這個概念,我們必須再次強調下面幾點:
HTTP 協議 未規定 GET 和POST的長度限制
GET的最大長度顯示是因為 瀏覽器和 web伺服器限制了 URI的長度
不同的瀏覽器和WEB伺服器,限制的最大長度不一樣
要支援IE,則最大長度為2083byte,若只支援Chrome,則最大長度 8182byte
補充補充一個get和post在快取方面的區別:
get請求類似於查詢的過程,使用者獲取資料,可以不用每次都與資料庫連線,所以可以使用快取。
post不同,post做的一般是修改和刪除的工作,所以必須與資料庫互動,所以不能使用快取。因此get請求適合於請求快取。
3、模組化發展歷程
可從IIFE、AMD、CMD、CommonJS、UMD、webpack(require。ensure)、ES Module、
使用 visibility替換 display: none,因為前者只會引起重繪,後者會引發迴流(改變了佈局)
把 DOM 離線後修改,比如:先把 DOM 給 display:none(有一次 Reflow),然後你修改100次,然後再把它顯示出來
不要把 DOM 結點的屬性值放在一個迴圈裡當成迴圈裡的變數
for(let i = 0; i < 1000; i++) {
// 獲取 offsetTop 會導致迴流,因為需要去獲取正確的值
console。log(document。querySelector(‘。test’)。style。offsetTop)
}
不要使用 table 佈局,可能很小的一個小改動會造成整個 table 的重新佈局
動畫實現的速度的選擇,動畫速度越快,迴流次數越多,也可以選擇使用 requestAnimationFrame
CSS 選擇符從右往左匹配查詢,避免 DOM 深度過深
將頻繁執行的動畫變為圖層,圖層能夠阻止該節點回流影響別的元素。比如對於 video標籤,瀏覽器會自動將該節點變為圖層。
react、Vue
1、寫 React / Vue 專案時為什麼要在列表元件中寫 key,其作用是什麼?
參考答案
vue和react都是採用diff演算法來對比新舊虛擬節點,從而更新節點。在vue的diff函式中(建議先了解一下diff演算法過程)。在交叉對比中,當新節點跟舊節點頭尾交叉對比沒有結果時,會根據新節點的key去對比舊節點陣列中的key,從而找到相應舊節點(這裡對應的是一個key => index 的map對映)。如果沒找到就認為是一個新增節點。而如果沒有key,那麼就會採用遍歷查詢的方式去找到對應的舊節點。一種一個map對映,另一種是遍歷查詢。相比而言。map對映的速度更快。vue部分原始碼如下:
// vue專案 src/core/vdom/patch。js -488行
// 以下是為了閱讀性進行格式化後的程式碼
// oldCh 是一箇舊虛擬節點陣列
if (isUndef(oldKeyToIdx)) {
oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
}
if(isDef(newStartVnode。key)) {
// map 方式獲取
idxInOld = oldKeyToIdx[newStartVnode。key]
} else {
// 遍歷方式獲取
idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
}
建立map函式
function createKeyToOldIdx (children, beginIdx, endIdx) {
let i, key
const map = {}
for (i = beginIdx; i <= endIdx; ++i) {
key = children[i]。key
if (isDef(key)) map[key] = i
}
return map
}
遍歷尋找
// sameVnode 是對比新舊節點是否相同的函式
function findIdxInOld (node, oldCh, start, end) {
for (let i = start; i < end; i++) {
const c = oldCh[i]
if (isDef(c) && sameVnode(node, c)) return i
}
}
2、React 中 setState 什麼時候是同步的,什麼時候是非同步的?
參考答案
在React中,如果是由React引發的事件處理(比如透過onClick引發的事件處理),呼叫setState不會同步更新this。state,除此之外的setState呼叫會同步執行this。state。所謂“除此之外”,指的是繞過React透過addEventListener直接新增的事件處理函式,還有透過setTimeout/setInterval產生的非同步呼叫。
**原因:**在React的setState函式實現中,會根據一個變數isBatchingUpdates判斷是直接更新this。state還是放到佇列中回頭再說,而isBatchingUpdates預設是false,也就表示setState會同步更新this。state,但是,有一個函式batchedUpdates,這個函式會把isBatchingUpdates修改為true,而當React在呼叫事件處理函式之前就會呼叫這個batchedUpdates,造成的後果,就是由React控制的事件處理過程setState不會同步更新this。state。
3、下面輸出什麼
class Example extends React。Component {
constructor() {
super();
this。state = {
val: 0
};
}
componentDidMount() {
this。setState({val: this。state。val + 1});
console。log(this。state。val); // 第 1 次 log
this。setState({val: this。state。val + 1});
console。log(this。state。val); // 第 2 次 log
setTimeout(() => {
this。setState({val: this。state。val + 1});
console。log(this。state。val); // 第 3 次 log
this。setState({val: this。state。val + 1});
console。log(this。state。val); // 第 4 次 log
}, 0);
}
render() {
return null;
}
};
1、第一次和第二次都是在 react 自身生命週期內,觸發時 isBatchingUpdates 為 true,所以並不會直接執行更新 state,而是加入了 dirtyComponents,所以列印時獲取的都是更新前的狀態 0。
2、兩次 setState 時,獲取到 this。state。val 都是 0,所以執行時都是將 0 設定成 1,在 react 內部會被合併掉,只執行一次。設定完成後 state。val 值為 1。
3、setTimeout 中的程式碼,觸發時 isBatchingUpdates 為 false,所以能夠直接進行更新,所以連著輸出 2,3。
輸出: 0 0 2 3
4、為什麼虛擬dom會提高效能?
參考答案
虛擬dom相當於在js和真實dom中間加了一個快取,利用dom diff演算法避免了沒有必要的dom操作,從而提高效能。
具體實現步驟如下:
用 JavaScript 物件結構表示 DOM 樹的結構;然後用這個樹構建一個真正的 DOM 樹,插到文件當中
當狀態變更的時候,重新構造一棵新的物件樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異
把2所記錄的差異應用到步驟1所構建的真正的DOM樹上,檢視就更新了。
css
1、分析比較 opacity: 0、visibility: hidden、display: none 優劣和適用場景
參考答案
結構:display:none: 會讓元素完全從渲染樹中消失,渲染的時候不佔據任何空間, 不能點選, visibility: hidden:不會讓元素從渲染樹消失,渲染元素繼續佔據空間,只是內容不可見,不能點選 opacity: 0: 不會讓元素從渲染樹消失,渲染元素繼續佔據空間,只是內容不可見,可以點選
繼承:display: none:是非繼承屬性,子孫節點消失由於元素從渲染樹消失造成,透過修改子孫節點屬性無法顯示。visibility: hidden:是繼承屬性,子孫節點消失由於繼承了hidden,透過設定visibility: visible;可以讓子孫節點顯式。
效能:displaynone : 修改元素會造成文件迴流,讀屏器不會讀取display: none元素內容,效能消耗較大 visibility:hidden: 修改元素只會造成本元素的重繪,效能消耗較少讀屏器讀取visibility: hidden元素內容 opacity: 0 :修改元素會造成重繪,效能消耗較少
聯絡:它們都能讓元素不可見
2、清除浮動的方式有哪些?比較好的是哪一種?
參考答案
常用的一般為三種。clearfix, clear:both,overflow:hidden;
比較好是 。clearfix,偽元素萬金油版本,後兩者有侷限性。
。clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: “ ”;
clear: both;
height: 0;
}
<!——
為毛沒有 zoom ,_height 這些,IE6,7這類需要 csshack 不再我們考慮之內了
。clearfix 還有另外一種寫法,
——>
。clearfix:before, 。clearfix:after {
content:“”;
display:table;
}
。clearfix:after{
clear:both;
overflow:hidden;
}
。clearfix{
zoom:1;
}
<!——
用display:table 是為了避免外邊距margin重疊導致的margin塌陷,
內部元素預設會成為 table-cell 單元格的形式
——>
clear:both:若是用在同一個容器內相鄰元素上,那是賊好的,有時候在容器外就有些問題了, 比如相鄰容器的包裹層元素塌陷
overflow:hidden:這種若是用在同個容器內,可以形成 BFC避免浮動造成的元素塌陷
4、css sprite 是什麼,有什麼優缺點
參考答案
概念:將多個小圖片拼接到一個圖片中。透過 background-position 和元素尺寸調節需要顯示的背景圖案。
優點:
減少 HTTP 請求數,極大地提高頁面載入速度
增加圖片資訊重複度,提高壓縮比,減少圖片大小
更換風格方便,只需在一張或幾張圖片上修改顏色或樣式即可實現
缺點:
圖片合併麻煩
維護麻煩,修改一個圖片可能需要重新佈局整個圖片,樣式
5、link與@import的區別
參考答案
link是 HTML 方式, @import是 CSS 方式
link最大限度支援並行下載,@import過多巢狀導致序列下載,出現FOUC
link可以透過rel=“alternate stylesheet”指定候選樣式
瀏覽器對link支援早於@import,可以使用@import對老瀏覽器隱藏樣式
@import必須在樣式規則之前,可以在 css 檔案中引用其他檔案
總體來說:link 優於@import
6、display: block;和display: inline;的區別
參考答案
block元素特點:
1。處於常規流中時,如果width沒有設定,會自動填充滿父容器 2。可以應用margin/padding 3。在沒有設定高度的情況下會擴充套件高度以包含常規流中的子元素 4。處於常規流中時佈局時在前後元素位置之間(獨佔一個水平空間) 5。忽略vertical-align
inline元素特點
1。水平方向上根據direction依次佈局
2。不會在元素前後進行換行
3。受white-space控制
4。margin/padding在豎直方向上無效,水平方向上有效
5。width/height屬性對非替換行內元素無效,寬度由元素內容決定
6。非替換行內元素的行框高由line-height確定,替換行內元素的行框高由height,margin,padding,border決定 7。浮動或絕對定位時會轉換為block8。vertical-align屬性生效
7、容器包含若干浮動元素時如何清理浮動
參考答案
容器元素閉合標籤前新增額外元素並設定clear: both
父元素觸發塊級格式化上下文(見塊級視覺化上下文部分)
設定容器元素偽元素進行清理推薦的清理浮動方法
/**
* 在標準瀏覽器下使用
* 1 content內容為空格用於修復opera下文件中出現
* contenteditable屬性時在清理浮動元素上下的空白
* 2 使用display使用table而不是block:可以防止容器和
* 子元素top-margin摺疊,這樣能使清理效果與BFC,IE6/7
* zoom: 1;一致
**/
。clearfix:before,
。clearfix:after {
content: “ ”; /* 1 */
display: table; /* 2 */
}
。clearfix:after {
clear: both;
}
/**
* IE 6/7下使用
* 透過觸發hasLayout實現包含浮動
**/
。clearfix {
*zoom: 1;
}
8、PNG,GIF,JPG 的區別及如何選
參考答案
GIF:
8 位畫素,256 色
無失真壓縮
支援簡單動畫
支援 boolean 透明
適合簡單動畫
JPEG:
顏色限於 256
有失真壓縮
可控制壓縮質量
不支援透明
適合照片
PNG:
有 PNG8 和 truecolor PNG
PNG8 類似 GIF 顏色上限為 256,檔案小,支援 alpha 透明度,無動畫
適合圖示、背景、按鈕
9、display,float,position 的關係
參考答案
如果display為 none,那麼 position 和 float 都不起作用,這種情況下元素不產生框
否則,如果 position 值為 absolute 或者 fixed,框就是絕對定位的,float 的計算值為 none,display 根據下面的表格進行調整。
否則,如果 float 不是 none,框是浮動的,display 根據下表進行調整
否則,如果元素是根元素,display 根據下表進行調整
其他情況下 display 的值為指定值 總結起來:絕對定位、浮動、根元素都需要調整display
10、如何水平居中一個元素
參考答案
如果需要居中的元素為常規流中 inline 元素,為父元素設定text-align: center;即可實現
如果需要居中的元素為常規流中 block 元素,1)為元素設定寬度,2)設定左右 margin 為 auto。3)IE6 下需在父元素上設定text-align: center;,再給子元素恢復需要的值
aaaaaa aaaaaa a a a a a a a a
body {
background: #DDD;
text-align: center; /* 3 */
}
。content {
width: 500px; /* 1 */
text-align: left; /* 3 */
margin: 0 auto; /* 2 */
background: purple;
}
如果需要居中的元素為浮動元素,1)為元素設定寬度,2)position: relative;,3)浮動方向偏移量(left 或者 right)設定為 50%,4)浮動方向上的 margin 設定為元素寬度一半乘以-1
aaaaaa aaaaaa a a a a a a a a
body {
background: #DDD;
}
。content {
width: 500px; /* 1 */
float: left;
position: relative; /* 2 */
left: 50%; /* 3 */
margin-left: -250px; /* 4 */
background-color: purple;
}
如果需要居中的元素為絕對定位元素,1)為元素設定寬度,2)偏移量設定為 50%,3)偏移方向外邊距設定為元素寬度一半乘以-1
aaaaaa aaaaaa a a a a a a a a
body {
background: #DDD;
position: relative;
}
。content {
width: 800px;
position: absolute;
left: 50%;
margin-left: -400px;
background-color: purple;
}
如果需要居中的元素為絕對定位元素,1)為元素設定寬度,2)設定左右偏移量都為 0,3)設定左右外邊距都為 auto
aaaaaa aaaaaa a a a a a a a a
body {
background: #DDD;
position: relative;
}
。content {
width: 800px;
position: absolute;
margin: 0 auto;
left: 0;
right: 0;
background-color: purple;
}
JavaScript
1、JS有幾種資料型別,其中基本資料型別有哪些?
參考答案
七種資料型別
Boolean
Null
Undefined
Number
String
Symbol (ECMAScript 6 新定義)
Object
(ES6之前)其中5種為基本型別:string,number,boolean,null,undefined,
ES6出來的Symbol也是原始資料型別 ,表示獨一無二的值
Object為引用型別(範圍挺大),也包括陣列、函式,
2、Promise 建構函式是同步執行還是非同步執行,那麼 then 方法呢?
參考答案
const promise = new Promise((resolve, reject) => {
console。log(1)
resolve()
console。log(2)
})
promise。then(() => {
console。log(3)
})
console。log(4)
輸出結果是:
1
2
4
3
promise建構函式是同步執行的,then方法是非同步執行的
Promise new的時候會立即執行裡面的程式碼 then是微任務 會在本次任務執行完的時候執行 setTimeout是宏任務 會在下次任務執行的時候執行
文章轉載:樂位元組