知識點漏缺總結

模塊化

使用模塊化可以給我們帶來以下好處

解決命名沖突

提供復用性

提高代碼可維護性

Proxy

Proxy 來替換原本的 Object.defineProperty 來實現數據響應式。 Proxy 是 ES6 中新增的功能,它可以用來自定義對象中的操作。

let p = new Proxy(target, handler)
復制代碼

target 代表需要添加代理的對象 ,handler 用來自定義對象中的操作,比如可以用來自定義 set 或者 get 函數。

接下來我們通過 Proxy 來實現一個數據響應式

let onWatch = (obj, setBind, getLogger) => {let handler = {get(target, property, receiver) {getLogger(target, property)return Reflect.get(target, property, receiver)},set(target, property, value, receiver) {setBind(value, property)return Reflect.set(target, property, value)}}return new Proxy(obj, handler)
}let obj = { a: 1 }
let p = onWatch(obj,(v, property) => {console.log(`監聽到屬性${property}改變為${v}`)},(target, property) => {console.log(`'${property}' = ${target[property]}`)}
)
p.a = 2 // 監聽到屬性a改變
p.a // 'a' = 2
復制代碼

在上述代碼中,我們通過自定義 set 和 get 函數的方式,在原本的邏輯中插入了我們的函數邏輯,實現了在對對象任何屬性進行讀寫時發出通知。

當然這是簡單版的響應式實現,如果需要實現一個 Vue 中的響應式,需要我們在 get 中收集依賴,在 set 派發更新,之所以 Vue3.0 要使用 Proxy 替換原本的 API 原因在于 Proxy 無需一層層遞歸為每個屬性添加代理,一次即可完成以上操作,性能上更好,并且原本的實現有一些數據更新不能監聽到,但是 Proxy 可以完美監聽到任何方式的數據改變,唯一缺陷可能就是瀏覽器的兼容性不好了。

reduce

const arr = [1, 2, 3]
const sum = arr.reduce((acc, current) => acc + current, 0)
console.log(sum)
復制代碼

對于 reduce 來說,它接受兩個參數,分別是回調函數和初始值,接下來我們來分解上述代碼中 reduce 的過程

首先初始值為 0,該值會在執行第一次回調函數時作為第一個參數傳入 回調函數接受四個參數,分別為累計值、當前元素、當前索引、原數組

在一次執行回調函數時,當前值和初始值相加得出結果1,

該結果會在第二次執行回調函數時當做第一個參數傳入。

所以在第二次執行回調函數時,相加的值就分別是 1 和2,以此類推,循環結束后得到結果 6

就通過 reduce 來實現 map和filter 函數

const numbers = [10, 20, 30, 40];
const go = numbers.reduce((finalList, num) => {//實現map方法,映射的作用num = num * 2;if (num > 50) {//實現filter方法過濾finalList.push(num);}return finalList;
}, []);alert(go); // [60, 80]復制代碼

setInterval

其實這個函數作用和 setTimeout 基本一致,只是該函數是每隔一段時間執行一次回調函數

通常來說不建議使用 setInterval。第一,它和 setTimeout 一樣,不能保證在預期的時間執行任務。第二,它存在執行累積的問題,請看以下偽代碼

function demo() {setInterval(function(){console.log(2)},1000)sleep(2000)
}
demo()
復制代碼

以上代碼在瀏覽器環境中,如果定時器執行過程中出現了耗時操作,多個回調函數會在耗時操作結束以后同時執行,這樣可能就會帶來性能上的問題。

如果你有循環定時器的需求,其實完全可以通過 requestAnimationFrame 來實現

特點

【1】requestAnimationFrame會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中就完成,并且重繪或回流的時間間隔緊緊跟隨瀏覽器的刷新頻率

??【2】在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或回流,這當然就意味著更少的CPU、GPU和內存使用量

??【3】requestAnimationFrame是由瀏覽器專門為動畫提供的API,在運行時瀏覽器會自動優化方法的調用,并且如果頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷

function setInterval(callback, interval) {let timerconst now = Date.nowlet startTime = now()let endTime = startTimeconst loop = () => {timer = window.requestAnimationFrame(loop)endTime = now()if (endTime - startTime >= interval) {startTime = endTime = now()callback(timer)}}timer = window.requestAnimationFrame(loop)return timer
}let a = 0
setInterval(timer => {console.log(1)a++if (a === 3) cancelAnimationFrame(timer)
}, 1000)
復制代碼

首先 requestAnimationFrame 自帶函數節流功能,基本可以保證在 16.6 毫秒內只執行一次(不掉幀的情況下),并且該函數的延時效果是精確的,沒有其他定時器時間不準的問題,當然你也可以通過該函數來實現 setTimeout。

進程與線程

進程和線程都是一個時間段的描述,是CPU工作時間段的描述。放在應用上來說就代表了一個程序。線程是進程中的更小單位,描述了執行一段指令所需的時間。

把這些概念拿到瀏覽器中來說,當你打開一個 Tab 頁時,其實就是創建了一個進程,一個進程中可以有多個線程,比如渲染線程、JS 引擎線程、HTTP 請求線程等等。當你發起一個請求時,其實就是創建了一個線程,當請求結束后,該線程可能就會被銷毀。

bind

和call很相似,第一個參數是this的指向,從第二個參數開始是接收的參數列表。區別在于bind方法返回值是函數以及bind接收的參數列表的使用。

bind返回值是函數

var obj = {name: 'Dot'
}function printName() {console.log(this.name)
}var dot = printName.bind(obj)
console.log(dot) // function () { … }
dot()  // Dot
復制代碼

bind 方法不會立即執行,而是 返回一個改變了上下文 this 后的函數。 而原函數 printName 中的 this 并沒有被改變,依舊指向全局對象 window。

參數的使用

function fn(a, b, c) {console.log(a, b, c);
}
var fn1 = fn.bind(null, 'Dot');fn('A', 'B', 'C');            // A B C
fn1('A', 'B', 'C');           // Dot A B
fn1('B', 'C');                // Dot B C
fn.call(null, 'Dot');      // Dot undefined undefined
復制代碼

call 是把第二個及以后的參數作為 fn 方法的實參傳進去,而 fn1 方法的實參實則是在 bind 中參數的基礎上再往后排。

有時候我們也用bind方法實現函數珂里化,以下是一個簡單的示例:

var add = function(x) {return function(y) {return x + y;};
};var increment = add(1);
var addTen = add(10);increment(2);
// 3addTen(2);
// 12
復制代碼

在低版本瀏覽器沒有 bind 方法,我們也可以自己實現一個。

if (!Function.prototype.bind) {Function.prototype.bind = function () {var self = this,                        // 保存原函數context = [].shift.call(arguments), // 保存需要綁定的this上下文args = [].slice.call(arguments);    // 剩余的參數轉為數組return function () {                    // 返回一個新函數self.apply(context, [].concat.call(args, [].slice.call(arguments)));}}
}
復制代碼

call apply bind應用場景

求數組中的最大和最小值

var arr = [1,2,3,89,46]var max = Math.max.apply(null,arr)//89var min = Math.min.apply(null,arr)//1
復制代碼

將類數組轉化為數組

var trueArr = Array.prototype.slice.call(arrayLike)
復制代碼

數組追加

var arr1 = [1,2,3];
var arr2 = [4,5,6];
var total = [].push.apply(arr1, arr2);//6
// arr1 [1, 2, 3, 4, 5, 6]
// arr2 [4,5,6]
復制代碼

判斷變量類型

function isArray(obj){return Object.prototype.toString.call(obj) == '[object Array]';
}
isArray([]) // true
isArray('dot') // false復制代碼

利用call和apply做繼承

function Person(name,age){// 這里的this都指向實例this.name = namethis.age = agethis.sayAge = function(){console.log(this.age)}
}
function Female(){Person.apply(this,arguments)//將父元素所有方法在這里執行一遍就繼承了
}
var dot = new Female('Dot',2)
復制代碼

使用 log 代理 console.log

function log(){console.log.apply(console, arguments);
}
// 當然也有更方便的 var log = console.log()
復制代碼

總結

call、apply和bind函數存在的區別:

bind返回對應函數, 便于稍后調用; apply, call則是立即調用。 除此外, 在 ES6 的箭頭函數下, call 和 apply 將失效, 對于箭頭函數來說:

箭頭函數體內的 this 對象, 就是定義時所在的對象,而不是使用時所在的對象;所以不需要類似于var _this = this這種丑陋的寫法

箭頭函數不可以當作構造函數,也就是說不可以使用 new 命令, 否則會拋出一個錯誤

箭頭函數不可以使用 arguments 對象,,該對象在函數體內不存在. 如果要用, 可以用 Rest 參數代替

不可以使用 yield 命令, 因此箭頭函數不能用作 Generator 函數

為什么 0.1 + 0.2 != 0.3

因為 JS 采用 IEEE 754 雙精度版本(64位),0.1 在二進制中是無限循環的一些數字,其實不只是 0.1,其實很多十進制小數用二進制表示都是無限循環的。 JS 采用的浮點數標準卻會裁剪掉我們的數字。 那么這些循環的數字被裁剪了,就會出現精度丟失的問題,也就造成了 0.1 不再是 0.1 了,而是變成了 0.100000000000000002

解決的辦法有很多,這里我們選用原生提供的方式來最簡單的解決問題

parseFloat((0.1 + 0.2).toFixed(10)) === 0.3 // true
復制代碼

存儲

cookie,localStorage,sessionStorage,indexDB

對于 cookie 來說,我們還需要注意安全性。

Service Worker

Service Worker 是運行在瀏覽器背后的獨立線程,一般可以用來實現緩存功能。 使用 Service Worker的話,傳輸協議必須為 HTTPS。因為 Service Worker 中涉及到請求攔截,所以必須使用 HTTPS 協議來保障安全。

Service Worker 實現緩存功能一般分為三個步驟:首先需要先注冊 Service Worker,然后監聽到 install 事件以后就可以緩存需要的文件,那么在下次用戶訪問的時候就可以通過攔截請求的方式查詢是否存在緩存,存在緩存的話就可以直接讀取緩存文件,否則就去請求數據。

瀏覽器緩存機制

緩存可以說是性能優化中簡單高效的一種優化方式了,它可以顯著減少網絡傳輸所帶來的損耗。

對于一個數據請求來說,可以分為發起網絡請求、后端處理、瀏覽器響應三個步驟瀏覽器緩存可以幫助我們在第一和第三步驟中優化性能。比如說直接使用緩存而不發起請求,或者發起了請求但后端存儲的數據和前端一致,那么就沒有必要再將數據回傳回來,這樣就減少了響應數據。

緩存位置

Service Worker

Memory Cache

Disk Cache

Push Cache

網絡請求

緩存策略

通常瀏覽器緩存策略分為兩種:強緩存和協商緩存,并且 緩存策略都是通過設置 HTTP Header 來實現的。

強緩存

強緩存可以通過設置兩種 HTTP Header 實現:Expires 和 Cache-Control 。

強緩存表示在緩存期間不需要請求,state code 為 200。

Expires

Expires: Wed, 22 Oct 2018 08:41:00 GMT Expires 是 HTTP/1 的產物,表示資源會在 Wed, 22 Oct 2018 08:41:00 GMT 后過期,需要再次請求。并且 Expires 受限于本地時間,如果修改了本地時間,可能會造成緩存失效。

Cache-control

Cache-control: max-age=30 Cache-Control 出現于 HTTP/1.1,優先級高于 Expires 。該屬性值表示資源會在 30 秒后過期,需要再次請求。

協商緩存

如果緩存過期了,就需要發起請求驗證資源是否有更新。協商緩存可以通過設置兩種 HTTP Header 實現 :Last-Modified 和 ETag 。

當瀏覽器發起請求驗證資源時,如果資源沒有做改變,那么服務端就會返回 304 狀態碼,并且更新瀏覽器緩存有效期。

Last-Modified 和 If-Modified-Since

Last-Modified 表示本地文件最后修改日期

If-Modified-Since 會將 Last-Modified 的值發送給服務器,詢問服務器在該日期后資源是否有更新,有更新的話就會將新的資源發送回來,否則返回 304 狀態碼。

但是 Last-Modified 存在一些弊端:

如果本地打開緩存文件,即使沒有對文件進行修改,但還是會造成 Last-Modified 被修改,服務端不能命中緩存導致發送相同的資源 因為 Last-Modified 只能以秒計時,如果在不可感知的時間內修改完成文件,那么服務端會認為資源還是命中了,不會返回正確的資源

因為以上這些弊端,所以在 HTTP / 1.1 出現了 ETag 。

ETag 和 If-None-Match

ETag 類似于文件指紋,If-None-Match 會將當前 ETag 發送給服務器,詢問該資源 ETag 是否變動,有變動的話就將新的資源發送回來。并且 ETag 優先級比 Last-Modified 高。

以上就是緩存策略的所有內容了,看到這里,不知道你是否存在這樣一個疑問。如果什么緩存策略都沒設置,那么瀏覽器會怎么處理?

對于這種情況,瀏覽器會采用一個啟發式的算法,通常會取響應頭中的 Date 減去 Last-Modified 值的 10% 作為緩存時間。

實際場景應用緩存策略

頻繁變動的資源

對于頻繁變動的資源,首先需要使用 Cache-Control: no-cache

使瀏覽器每次都請求服務器,然后配合 ETag 或者 Last-Modified 來驗證資源是否有效。這樣的做法雖然不能節省請求數量,但是能顯著減少響應數據大小。

代碼文件

這里特指除了 HTML 外的代碼文件,因為 HTML 文件一般不緩存或者緩存時間很短。

一般來說,現在都會使用工具來打包代碼,那么我們就可以對文件名進行哈希處理,只有當代碼修改后才會生成新的文件名。基于此,我們就可以給代碼文件設置緩存有效期一年 Cache-Control: max-age=31536000,這樣只有當 HTML 文件中引入的文件名發生了改變才會去下載最新的代碼文件,否則就一直使用緩存。

瀏覽器渲染原理

瀏覽器從網絡中接收到 HTML 文件然后一系列的轉換過程。

接下來就是css樹與dom樹合并成渲染樹。渲染樹只會包括需要顯示的節點和這些節點的樣式信息,如果某個節點是 display: none 的,那么就不會在渲染樹中顯示。

為什么操作 DOM 慢

因為 DOM 是屬于渲染引擎中的東西,而 JS 又是 JS 引擎中的東西。當我們通過 JS 操作 DOM 的時候,其實 這個操作涉及到了兩個線程之間的通信,那么勢必會帶來一些性能上的損耗。 操作 DOM 次數一多,也就等同于一直在進行線程之間的通信,并且操作 DOM 可能還會帶來重繪回流的情況,所以也就導致了性能上的問題。

經典面試題:插入幾萬個 DOM,如何實現頁面不卡頓?

大部分人應該可以想到通過 requestAnimationFrame (requestAnimationFrame會把每一幀中的所有DOM操作集中起來,在一次重繪或回流中就完成,并且重繪或回流的時間間隔緊緊跟隨瀏覽器的刷新頻率)的方式去循環的插入 DOM。

其實還有種方式去解決這個問題:虛擬滾動(virtualized scroller)。

這種技術的原理就是只渲染可視區域內的內容,非可見區域的那就完全不渲染了,當用戶在滾動的時候就實時去替換渲染的內容。

什么情況阻塞渲染

首先渲染的前提是生成渲染樹,所以 HTML 和 CSS 肯定會阻塞渲染。如果你想渲染的越快,你越應該降低一開始需要渲染的文件大小,并且扁平層級,優化選擇器。

然后當瀏覽器在解析到 script 標簽時,會暫停構建 DOM,完成后才會從暫停的地方重新開始。也就是說,如果你想首屏渲染的越快,就越不應該在首屏就加載 JS 文件,這也是都建議將 script 標簽放在 body 標簽底部的原因。

當然在當下,并不是說 script 標簽必須放在底部,因為你可以給 script 標簽添加 defer 或者 async 屬性。

當 script 標簽加上 defer 屬性以后,表示該 JS 文件會并行下載,但是會放到 HTML 解析完成后順序執行,所以對于這種情況你可以把 script 標簽放在任意位置。

對于沒有任何依賴的 JS 文件可以加上 async 屬性,表示 JS 文件下載和解析不會阻塞渲染。

減少重繪和回流

使用 transform 替代 top

<div class="test"></div>
<style>.test {position: absolute;top: 10px;width: 100px;height: 100px;background: red;}
</style>
<script>setTimeout(() => {// 引起回流document.querySelector('.test').style.top = '100px'}, 1000)
</script>
復制代碼

使用 visibility 替換 display: none ,因為前者只會引起重繪,后者會引發回流(改變了布局)

不要把節點的屬性值放在一個循環里當成循環里的變量

for(let i = 0; i < 1000; i++) {// 獲取 offsetTop 會導致回流,因為需要去獲取正確的值console.log(document.querySelector('.test').style.offsetTop)
}
復制代碼

不要使用 table 布局,可能很小的一個小改動會造成整個 table 的重新布局

動畫實現的速度的選擇,動畫速度越快,回流次數越多,也可以選擇使用 requestAnimationFrame

CSS 選擇符從右往左匹配查找,所以要避免節點層級過多

將頻繁重繪或者回流的節點設置為圖層,圖層能夠阻止該節點的渲染行為影響別的節點。比如對于 video 標簽來說,瀏覽器會自動將該節點變為圖層。

設置節點為圖層的方式有很多,我們可以通過以下幾個常用屬性可以生成新圖層

will-change

video、iframe 標簽

在不考慮緩存和優化網絡協議的前提下,考慮可以通過哪些方式來最快的渲染頁面,也就是常說的關鍵渲染路徑,這部分也是性能優化中的一塊內容。

當發生 DOMContentLoaded 事件后,就會生成渲染樹,生成渲染樹就可以進行渲染了,這一過程更大程度上和硬件有關系了。

提示如何加速:

從文件大小考慮

從 script 標簽使用上來考慮

從 CSS、HTML 的代碼書寫上來考慮

從需要下載的內容是否需要在首屏使用上來考慮

性能優化

圖片優化

計算圖片大小

對于一張 100 * 100 像素的圖片來說,圖像上有 10000 個像素點,如果每個像素的值是 RGBA 存儲的話,那么也就是說每個像素有 4 個通道,每個通道 1 個字節(8 位 = 1個字節),所以該圖片大小大概為 39KB(10000 * 1 * 4 / 1024)。

減少像素點

減少每個像素點能夠顯示的顏色

圖片加載優化

1、修飾圖片完全可以用 CSS 去代替。

2、沒有必要去加載原圖浪費帶寬。一般圖片都用 CDN加載,可以計算出適配屏幕的寬度,然后去請求相應裁剪好的圖片。

3、小圖使用 base64 格式

4、將多個圖標文件整合到一張圖片中(雪碧圖)

5.選擇正確的圖片格式:

對于能夠顯示 WebP 格式的瀏覽器盡量使用 WebP 格式。因為 WebP 格式具有更好的圖像數據壓縮算法,能帶來更小的圖片體積, 而且擁有肉眼識別無差異的圖像質量,缺點就是兼容性并不好 小圖使用 PNG,其實對于大部分圖標這類圖片,完全可以使用 SVG 代替 照片使用 JPEG

DNS 預解析

DNS 解析也是需要時間的,可以通過預解析的方式來預先獲得域名所對應的 IP。

<link rel="dns-prefetch" href="//yuchengkai.cn">
復制代碼

防抖節流也是性能優化

預加載

有些資源不需要馬上用到,但是希望盡早獲取,這時候就可以使用預加載。

預加載其實 是聲明式的 fetch強制瀏覽器請求資源,并且不會阻塞 onload 事件,可以使用以下代碼開啟預加載

<link rel="preload" href="http://example.com">
復制代碼

預加載可以一定程度上降低首屏的加載時間,因為可以將一些不影響首屏但重要的文件延后加載,唯一缺點就是兼容性不好。

預渲染

可以通過預渲染將下載的文件預先在后臺渲染,可以使用以下代碼開啟預渲染

<link rel="prerender" href="http://example.com"> 
復制代碼

預渲染雖然可以提高頁面的加載速度,但是要確保該頁面大概率會被用戶在之后打開,否則就是白白浪費資源去渲染。

懶加載

懶加載的原理就是只加載可視區域,但也可以是即將進入可視區域)內需要加載的東西。對于圖片來說,先設置圖片標簽的 src 屬性為一張占位圖,將真實的圖片資源放入一個自定義屬性中,當進入可視區域時,就將自定義屬性替換為 src 屬性,這樣圖片就會去下載資源,實現了圖片懶加載。

CDN

CDN 的原理是盡可能的在各個地方分布機房緩存數據,這樣即使我們的根服務器遠在國外,在國內的用戶也可以通過國內的機房迅速加載資源。

因此,我們可以將靜態資源盡量使用 CDN 加載,由于瀏覽器對于單個域名有并發請求上限,可以考慮使用多個 CDN 域名。并且對于 CDN 加載靜態資源需要注意 CDN 域名要與主站不同,否則每次請求都會帶上主站的 Cookie,平白消耗流量。

Webpack 性能優化

減少 Webpack 打包時間

優化 Loader

對于 Loader 來說,影響打包效率首當其沖必屬 Babel 了。因為 Babel 會將代碼轉為字符串生成 AST,然后對 AST 繼續進行轉變最后再生成新的代碼,項目越大,轉換代碼越多,效率就越低。

優化方法:

1、首先我們可以優化 Loader 的文件搜索范圍,只作用在 JS 代碼上的,然后 node_modules 中使用的代碼都是編譯過的,所以我們也完全沒有必要再去處理一遍

2、將 Babel 編譯過的文件緩存起來(下次只需要編譯更改過的代碼文件即可,這樣可以大幅度加快打包時間)

MVVM

首先先申明一點,不管是 React 還是 Vue,它們都不是 MVVM 框架,只是有借鑒 MVVM 的思路。文中拿 Vue 舉例也是為了更好地理解 MVVM 的概念。

傳統的 MVC 架構通常是使用控制器更新模型,視圖從模型中獲取數據去渲染。當用戶有輸入時,會通過控制器去更新模型,并且通知視圖進行更新。

但是MVC 有一個巨大的缺陷就是控制器承擔的責任太大了,隨著項目愈加復雜,控制器中的代碼會越來越臃腫,導致出現不利于維護的情況。

在 MVVM 架構中,引入了 ViewModel 的概念。ViewModel 只關心數據和業務的處理,不關心 View 如何處理數據,在這種情況下,View 和 Model 都可以獨立出來,任何一方改變了也不一定需要改變另一方,并且可以將一些可復用的邏輯放在一個 ViewModel 中,讓多個 View 復用這個 ViewModel。

以 Vue 框架來舉例,ViewModel 就是組件的實例。View 就是模板,Model 的話在引入 Vuex 的情況下是完全可以和組件分離的。

除了以上三個部分,其實在 MVVM 中還引入了一個隱式的 Binder 層,實現了 View 和 ViewModel 的綁定。

同樣以 Vue 框架來舉例,這個隱式的 Binder 層就是 Vue 通過解析模板中的插值和指令從而實現 View 與 ViewModel 的綁定。

對于 MVVM 來說,其實最重要的并不是通過雙向綁定或者其他的方式將 View 與 ViewModel 綁定起來,而是通過 ViewModel 將視圖中的狀態和用戶的行為分離出一個抽象,這才是 MVVM 的精髓。

路由原理

前端路由實現起來其實很簡單,本質就是監聽 URL 的變化,然后匹配路由規則,顯示相應的頁面,并且無須刷新頁面。目前前端使用的路由就只有兩種實現方式

Hash 模式

History 模式

Hash 模式

www.test.com/#/ 就是 Hash URL,當 # 后面的哈希值發生變化時,可以通過 hashchange 事件來監聽到 URL 的變化,從而進行跳轉頁面,并且無論哈希值如何變化,服務端接收到的 URL 請求永遠是 www.test.com。

window.addEventListener('hashchange', () => {// ... 具體邏輯
})
復制代碼

Hash 模式相對來說更簡單,并且兼容性也更好。

History 模式

History 模式是 HTML5 新推出的功能,主要使用 history.pushState 和 history.replaceState 改變 URL。

通過 History 模式改變 URL 同樣不會引起頁面的刷新,只會更新瀏覽器的歷史記錄。

// 新增歷史記錄
history.pushState(stateObject, title, URL)
// 替換當前歷史記錄
history.replaceState(stateObject, title, URL)
復制代碼

當用戶做出瀏覽器動作時,比如點擊后退按鈕時會觸發 popState 事件

window.addEventListener('popstate', e => {// e.state 就是 pushState(stateObject) 中的 stateObjectconsole.log(e.state)
})
復制代碼

兩種模式對比

Hash 模式只可以更改 # 后面的內容,History 模式可以通過 API 設置任意的同源 URL

History 模式可以通過 API 添加任意類型的數據到歷史記錄中,Hash 模式只能更改哈希值,也就是字符串

Hash 模式無需后端配置,并且兼容性好。History 模式在用戶手動輸入地址或者刷新頁面的時候會發起 URL 請求,后端需要配置 index.html 頁面用于匹配不到靜態資源的時候

computed 和 watch 區別

computed 是計算屬性,依賴其他屬性計算值,來動態獲得值并且 computed 的值有緩存,只有當計算值變化才會返回內容。

watch 監聽到值的變化就會執行回調,在回調中可以進行一些復雜業務邏輯操作。

keep-alive 組件有什么作用

如果你需要在組件切換的時候,保存一些組件的狀態防止多次渲染,就可以使用 keep-alive 組件包裹需要保存的組件。

對于 keep-alive 組件來說,它擁有兩個獨有的生命周期鉤子函數,分別為 activated 和 deactivated 。用 keep-alive 包裹的組件在切換時不會進行銷毀,而是緩存到內存中并執行 deactivated 鉤子函數,命中緩存渲染后會執行 actived 鉤子函數。

Vue進階知識

Object.defineProperty 的缺陷

如果通過下標方式修改數組數據或者給對象新增屬性并不會觸發組件的重新渲染,因為 Object.defineProperty 不能攔截到這些操作,更精確的來說,對于數組而言,大部分操作都是攔截不到的

所以 Vue 內部通過重寫函數的方式解決了這個問題。

編譯過程

將模板解析為 AST

優化 AST

將 AST 轉換為 render 函數

NextTick 原理分析

nextTick 可以讓我們在下次 DOM 更新循環結束之后執行延遲回調,用于獲得更新后的 DOM。

持續補充

關于function a()與var a = function()

 mili();function mili() {console.log('mili');}mogu();var mogu = function () {console.log('mogu');};
復制代碼

打印結果是:mili Typeerror:mogu is not a function

原因 :因為通過function a ()這種方式是函數聲明和賦值都提前了。而通過var a = function 則只是函數聲明提前了,而賦值要到執行到var a = function這步才會賦值。

瀏覽器緩存圖解

window.onload和document.ready的區別

最基本區別

1.執行時間

window.onload必須等到頁面內包括圖片的所有元素加載完畢后再去執行。

$(document).ready()時DOM結構回執完畢后就執行,不必等到加載完畢。

2.編寫個數不同

window.onload不同同時編寫多個,如果有多個window.onload方法,只會執行一個

$(document).ready()可以同時編寫多個,并且可以得到執行

document.onDOMContentLoaded在頁面中觸發[DOMContentLoaded]事件時觸發。此時,文檔被加載和解析,并且DOM被完全構造,但鏈接的資源(例如圖像,樣式表和子幀)可能尚未被加載。

轉載于:https://juejin.im/post/5ca36b7fe51d4501f311a1a6

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449019.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449019.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449019.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

成功投資的九大要訣

真正的有錢人對金錢持非常嚴肅的態度&#xff0c;即便是拿來投機也要小心睿智&#xff0c;物盡其用。這里的投機并不是指非理性的賭博&#xff0c;而是指為了追求更高收益而采取的市場投資行為。卡西研究所資深分析師Louis James總結了富豪們投機成功的9個秘訣。 秘訣1&#…

《 Docker 技術入門與實戰 》讀書筆記 ( CentOS 安裝 Docker )

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 PS &#xff1a;個人所有讀書筆記只記錄個人想要的內容&#xff0c;很可能原書大量內容沒有納入筆記中... ... 以下全文內容出自書目&…

數據結構:靜態鏈表實現樹的同構

寫在最前面 按照課程講解的思路來寫&#xff0c;邏輯關系能夠理解清楚了&#xff0c;但是實際運行起來實在是有問題&#xff0c;雖然在PTA上能夠通過。但是我自己看不出問題來&#xff0c;并且&#xff0c;看了一遍又一遍仍然看不出來&#xff01;&#xff08;可能自己太笨。。…

中國人為什么學不會英語

英語永遠也學不會! 這種抱怨和哀嘆&#xff0c;大概在中國早已經司空見慣了。于是&#xff0c;有人開始計算學英語是多么大的浪費。 作為過來人&#xff0c;我對此深有體會。記得我當年也有過類似的絕望感。 但是&#xff0c;一位前輩安慰我說&#xff1a;你可以說你永遠掌…

研究人員發現:基于文本的AI模型容易受到改述攻擊

由于自然語言處理&#xff08;NLP&#xff09;的進步&#xff0c;越來越多的公司和組織開始利用AI算法來執行與文本相關的任務&#xff0c;例如&#xff1a;過濾垃圾郵件、分析社交媒體帖子和評論、評估簡歷以及檢測假新聞。 但是&#xff0c;真的可以相信這些算法能夠可靠地執…

解決 linux 下安裝 node 報: command not found

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 注意&#xff1a;有時安裝成功后,需要關閉xshell&#xff0c;重新啟動。nvm才會生效。 1. 在 linux 下安裝 node 提示 -bash: node: com…

阿里云官方網站免費套餐怎么搶

阿里云推出包含云服務器 ECS、負載均衡、云數據庫 RDS、云數據庫 Redis 版、云數據庫 Mongodb 版、彈性公網 IP、CDN、對象存儲 OSS、文件存儲 NAS等40核心云產品&#xff0c;6個月免費使用何為免費套餐&#xff0c;其實就是讓你先體驗&#xff0c;覺得好用&#xff0c;易用&am…

1003 我要通過

1003 我要通過&#xff01; (20 分)“答案正確”是自動判題系統給出的最令人歡喜的回復。本題屬于 PAT 的“答案正確”大派送 —— 只要讀入的字符串滿足下列條件&#xff0c;系統就輸出“答案正確”&#xff0c;否則輸出“答案錯誤”。 得到“答案正確”的條件是&#xff1a; …

在英特爾? 凌動? 處理器上將 OpenGL* 游戲移植到 Android* (第一部分)

將游戲和其他使用大量 3D 圖形的應用從 OpenGL 標準移植到 Google Android 設備&#xff08;包括構建在英特爾 凌動? 微架構上的設備&#xff09;存在巨大的機遇&#xff0c;因為基于 OpenGL 的游戲、游戲引擎和其他傳統軟件易于獲得&#xff1b;OpenGL 便于移植&#xff1b;而…

文件系統:使用 yum 安裝軟件包

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 一、yum命令的基本安裝功能 [rootlocalhost ~]# man yum command is one of: * install package1 [package2] [...]&#xff1a; ins…

elasticsearch全局analyzer聲明

2019獨角獸企業重金招聘Python工程師標準>>> 問題 elasticsearch從2.4升級到5.6&#xff0c;elasticsearch.yml配置中有一些analyzer配置拷貝到新版本&#xff0c;啟動報錯 index :analysis :analyzer :lowercase_whitespace :type : customtokenizer : myTokenizer…

Parallels Desktop虛擬機無法關機提示“虛擬機處理器已被操作系統重置”

如果你在使用PD的時候遇到了這樣子的彈窗&#xff0c;恭喜你篇博文可以幫助你&#xff0c;因為我剛剛也遇到了這個問題。如果有幫助可以點一下推薦按鈕。 針對Windows電腦 啟動虛擬機創建快照使用管理員權限運行命令提示符執行powercfg -h off重啟試試成功了再刪除快照即可修改…

linux下安裝 ping 命令

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 使用docker倉庫下載的ubuntu 14.04 鏡像。里面精簡的連 ping 命令都沒有。google 百度都搜索不到ping 命令在哪個包里。 努力找了半天&…

揚尼斯定律:程序員的開發效率每6年提高一倍

我不斷的聽到各種關于“軟件危機”的警言&#xff0c;以及關于軟件開發缺少過程規范的批評。我做編程工作超過15年&#xff0c;我認為這些言論基本上都是錯的&#xff1a;我確信我能在很短的時間里用如今的開發工具復制出15年前一個不錯的程序員開發出的東西。 模仿摩爾定律和…

ApiBoot - ApiBoot Quartz 使用文檔

ApiBoot Quartz ApiBoot內部集成了Quartz&#xff0c;提供了數據庫方式、內存方式的進行任務的存儲&#xff0c;其中數據庫方式提供了分布式集群任務調度&#xff0c;任務自動平滑切換執行節點。 引用ApiBoot Quartz 在pom.xml配置文件內添加&#xff0c;如下配置&#xff1a; …

《算法競賽進階指南》0.4二分

102. 最佳牛圍欄 農夫約翰的農場由N塊田地組成&#xff0c;每塊地里都有一定數量的牛,其數量不會少于1頭&#xff0c;也不會超過2000頭。 約翰希望用圍欄將一部分連續的田地圍起來&#xff0c;并使得圍起來的區域內每塊地包含的牛的數量的平均值達到最大。 圍起區域內至少需要包…

Hibernate 自動創建表

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 在 hibernate.cfg.xml 添加這句話&#xff0c;可以自動生成數據表 : <property name"hibernate.hbm2ddl.auto">upd…

程序員越老越優秀嗎?

Peter Knego 向我們展示了一些有趣的東西&#xff1a; 官方數據&#xff1a;程序員年紀越大越出色、越稀有。他使用StackOverflow的聲譽值和其它幾個指標來印證他的觀點。 他的總結是&#xff1a; 隨著年齡的增加&#xff0c;程序員的數量急劇下降。程序員數量的峰值出現在2…

小程序學習(一):點擊愛心變色 -- 最簡單的事件實現

最近在學習小程序&#xff0c;想通過寫文章來記錄自己的學習歷程&#xff0c;希望能做到每周都寫…… 如何綁定一個事件 微信小程序中&#xff0c;綁定事件要在標簽內寫入這兩段代碼&#xff1a; bindtap"fnActive" data-favourite "{{isLike}}" 復制代碼…

安全通信

安全通信 應用層協議大多數自己都沒有實現加解密功能&#xff0c;比如http等。http就是直接把數據加載進來然后做簡單編碼&#xff08;也就是流式化&#xff09;然后響應客戶端&#xff0c;然后數據在瀏覽器展示&#xff0c;這個數據在傳輸過程是明文的&#xff0c;你截獲就可以…