您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)如何優(yōu)化Javascript前端代碼,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
1、能夠嵌入動(dòng)態(tài)文本于HTML頁(yè)面。2、對(duì)瀏覽器事件做出響應(yīng)。3、讀寫HTML元素。4、在數(shù)據(jù)被提交到服務(wù)器之前驗(yàn)證數(shù)據(jù)。5、檢測(cè)訪客的瀏覽器信息。6、控制cookies,包括創(chuàng)建和修改等。7、基于Node.js技術(shù)進(jìn)行服務(wù)器端編程。
JavaScript條件語(yǔ)句在我們平時(shí)的開發(fā)中是不可避免要用到的,但是很多時(shí)候我們的代碼寫的并不好,一連串的if-else或者多重嵌套判斷都會(huì)使得代碼很臃腫,下面舉例進(jìn)行優(yōu)化。
需求:現(xiàn)在有 4 個(gè)產(chǎn)品,分別是手機(jī)、電腦、電視機(jī)、游戲機(jī),當(dāng)然每個(gè)產(chǎn)品顯示的價(jià)格不一樣。
let commodity = { phone: '手機(jī)', computer: '電腦', television: '電視', gameBoy: '游戲機(jī)', } function price(name) { if (name === commodity.phone) { console.log(1999) } else if (name === commodity.computer) { console.log(9999) } else if (name === commodity.television) { console.log(2999) } else if (name === commodity.gameBoy) { console.log(3999) } } price('手機(jī)') // 9999
缺點(diǎn):代碼太長(zhǎng)了,維護(hù)和閱讀都很不友好
let commodity = { phone: '手機(jī)', computer: '電腦', television: '電視', gameBoy: '游戲機(jī)', } const price = (name) => { switch (name) { case commodity.phone: console.log(1999) break case commodity.computer: console.log(9999) break case commodity.television: console.log(2999) break case commodity.gameBoy: console.log(3999) break } } price('手機(jī)') // 9999
策略模式利用組合、委托和多態(tài)等技術(shù)和思想,可以有效地避免多重條件選擇語(yǔ)句。它提供了對(duì)開放—封閉原則的完美支持,將算法封裝在獨(dú)立的 strategy 中,使得它們易于切換,易于理解,易于擴(kuò)展。
const commodity = new Map([ ['phone', 1999], ['computer', 9999], ['television', 2999], ['gameBoy', 3999], ]) const price = (name) => { return commodity.get(name) } price('phone') // 1999
includes是 ES7 新增的 API,與indexOf不同的是includes直接返回的是Boolean值,indexOf則 返回的索引值, 數(shù)組和字符串都有includes方法。
需求:我們來實(shí)現(xiàn)一個(gè)身份認(rèn)證方法,通過傳入身份 Id 返回對(duì)應(yīng)的驗(yàn)證結(jié)果
傳統(tǒng)方法
function verifyIdentity(identityId) { if (identityId == 1 || identityId == 2 || identityId == 3 || identityId == 4) { return '你的身份合法,請(qǐng)通行!' } else { return '你的身份不合法' } }
includes優(yōu)化
function verifyIdentity(identityId) { if ([1, 2, 3, 4].includes(identityId)) { return '你的身份合法,請(qǐng)通行!' } else { return '你的身份不合法' } }
在 JavaScript 中,我們可以使用for(),while(),for(in),for(in)幾種循環(huán),事實(shí)上,這三種循環(huán)中for(in)的效率極差,因?yàn)樗枰樵兩⒘墟I,所以應(yīng)該盡量少用。
for 循環(huán)是最傳統(tǒng)的語(yǔ)句,它以變量 i 作為索引,以跟蹤訪問的位置,對(duì)數(shù)組進(jìn)行操作。
var arr = ['a', 'b', 'c'] for (var i = 0; i < arr.length; i++) { console.log(arr[i]) //結(jié)果依次a,b,c }
以上的方法有一個(gè)問題:就是當(dāng)數(shù)組的長(zhǎng)度到達(dá)百萬(wàn)級(jí)時(shí),arr.length就要計(jì)算一百萬(wàn)次,這是相當(dāng)耗性能的。所以可以采用以下方法就行改良。
var arr = ['a', 'b', 'c'] for (var i = 0, length = arr.length; i < length; i++) { console.log(arr[i]) //結(jié)果依次a,b,c }
此時(shí)arr.length只需要計(jì)算一次,優(yōu)化了性能。
for-in一般用來來遍歷對(duì)象的屬性的,不過屬性需要enumerable(可枚舉)才能被讀取到。同時(shí)for-in也可以遍歷數(shù)組,遍歷數(shù)組的時(shí)候遍歷的是數(shù)組的下標(biāo)值。
var obj = { 0: 'a', 1: 'b', 2: 'c' } for (var key in obj) { console.log(key) //結(jié)果為依次為0,1,2 } var arr = ['a', 'b', 'c'] for (var key in a) { console.log(key) //結(jié)果為依次為0,1,2 }
for-of語(yǔ)句看著有點(diǎn)像for-in語(yǔ)句,但是和for-of語(yǔ)句不同的是它不可以循環(huán)對(duì)象,只能循環(huán)數(shù)組。
var arr = ['a', 'b', 'c'] for (var value of arr) { console.log(value) // 結(jié)果依次為a,b,c }
for-of比f(wàn)or-in循環(huán)遍歷數(shù)組更好。for-of只要具有Iterator接口的數(shù)據(jù)結(jié)構(gòu),都可以使用它迭代成員。它直接讀取的是鍵值。for-in需要窮舉對(duì)象的所有屬性,包括自定義的添加的屬性也能遍歷到。且for-in的key是String類型,有轉(zhuǎn)換過程,開銷比較大。
所以在開發(fā)過程中循環(huán)數(shù)組盡量避免使用for-in。
數(shù)組去重是實(shí)際開發(fā)處理數(shù)據(jù)中經(jīng)常遇到的,方法有很多,這里就不一一例舉了。
function unique4(arr) { var newArr = [] for (var i = 0; i < arr.length; i++) { if (newArr.indexOf(arr[i]) === -1) { newArr.push(arr[i]) } } return newArr } console.log(unique4([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4])) // [1, 2, 3, 5, 6, 7, 4]
Set本身是一個(gè)構(gòu)造函數(shù),用來生成Set數(shù)據(jù)結(jié)構(gòu)。Set函數(shù)可以接受一個(gè)數(shù)組(或者具有 iterable 接口的其他數(shù)據(jù)結(jié)構(gòu))作為參數(shù),用來初始化。Set對(duì)象允許你存儲(chǔ)任何類型的值,無論是原始值或者是對(duì)象引用。它類似于數(shù)組,但是成員的值都是唯一的,沒有重復(fù)的值。
function unique4(arr) { return Array.from(new Set(arr)) // 利用Array.from將Set結(jié)構(gòu)轉(zhuǎn)換成數(shù)組 } console.log(unique4([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4])) // [1, 2, 3, 5, 6, 7, 4]
箭頭函數(shù)表達(dá)式的語(yǔ)法比函數(shù)表達(dá)式更簡(jiǎn)潔。所以在開發(fā)中更推薦使用箭頭函數(shù)。特別是在vue項(xiàng)目中,使用箭頭函數(shù)不需要在更this重新賦一個(gè)變量。
// 使用functions var arr = [5, 3, 2, 9, 1] var arrFunc = arr.map(function (x) { return x * x }) console.log(arrFunc) // 使用箭頭函數(shù) var arr = [5, 3, 2, 9, 1] var arrFunc = arr.map((x) => x * x)
要注意的是,箭頭函數(shù)不綁定arguments,取而代之用rest參數(shù)…解決。
// 不能使用 arguments let fun1 = (b) => { console.log(arguments) } fun1(2, 92, 32, 32) // Uncaught ReferenceError: arguments is not defined // 使用rest 參數(shù) let fun2 = (...c) => { console.log(c) } fun2(3, 82, 32, 11323) // [3, 82, 32, 11323]
創(chuàng)建多個(gè) dom 元素時(shí),先將元素append到DocumentFragment中,最后統(tǒng)一將DocumentFragment添加到頁(yè)面。
常規(guī)方法;
for (var i = 0; i < 1000; i++) { var el = document.createElement('p') el.innerhtml = i document.body.appendChild(el) }
使用DocumentFragment優(yōu)化多次append
var frag = document.createDocumentFragment() for (var i = 0; i < 1000; i++) { var el = document.createElement('p') el.innerhtml = i frag.appendChild(el) } document.body.appendChild(frag)
更優(yōu)的方法:使用一次innerHTML賦值代替構(gòu)建 dom 元素
var html = [] for (var i = 0; i < 1000; i++) { html.push('<p>' + i + '</p>') } document.body.innerHTML = html.join('')
系統(tǒng)進(jìn)程不再用到的內(nèi)存,沒有及時(shí)釋放,就叫做內(nèi)存泄漏(memory leak)。當(dāng)內(nèi)存占用越來越高,輕則影響系統(tǒng)性能,重則導(dǎo)致進(jìn)程崩潰。
引起內(nèi)存泄漏的原因
全局變量
function fn() { a = "Actually, I'm a global variable" } fn() function fn() { this.a = "Actually, I'm a global variable" } fn()
解決方法:
避免創(chuàng)建全局變量
使用嚴(yán)格模式,在 JavaScript 文件頭部或者函數(shù)的頂部加上use strict。
<template> <div id="home"> 這里是首頁(yè) </div> </template> <script> export default { mounted() { window.test = { // 此處在全局window對(duì)象中引用了本頁(yè)面的dom對(duì)象 name: 'home', node: document.getElementById('home') } } } </script>
解決方案: 在頁(yè)面卸載的時(shí)候順便處理掉該引用。
destroyed () { window.test = null // 頁(yè)面卸載的時(shí)候解除引用 }
閉包
閉包引起的內(nèi)存泄漏原因:閉包可以維持函數(shù)內(nèi)局部變量,使其得不到釋放。
function fn() { var a = "I'm a" return function () { console.log(a) } }
解決:將事件處理函數(shù)定義在外部,解除閉包,或者在定義事件處理函數(shù)的外部函數(shù)中,刪除對(duì) dom 的引用。
定時(shí)器或事件監(jiān)聽
由于項(xiàng)目中有些頁(yè)面難免會(huì)碰到需要定時(shí)器或者事件監(jiān)聽。但是在離開當(dāng)前頁(yè)面的時(shí)候,定時(shí)器如果不及時(shí)合理地清除,會(huì)造成業(yè)務(wù)邏輯混亂甚至應(yīng)用卡死的情況,這個(gè)時(shí)就需要清除定時(shí)器事件監(jiān)聽,即在頁(yè)面卸載(關(guān)閉)的生命周期函數(shù)里,清除定時(shí)器。
methods:{ resizeFun () { this.tableHeight = window.innerHeight - document.getElementById('table').offsetTop - 128 }, setTimer() { this.timer = setInterval(() => { }) }, clearTimer() {//清除定時(shí)器 clearInterval(this.timer) this.timer = null } }, mounted() { this.setTimer() window.addEventListener('resize', this.resizeFun) }, beforeDestroy() { window.removeEventListener('resize', this.resizeFun) this.clearTimer() }
在前端開發(fā)的過程中,我們經(jīng)常會(huì)需要綁定一些持續(xù)觸發(fā)的事件,如resize、scroll、mousemove等等,但有些時(shí)候我們并不希望在事件持續(xù)觸發(fā)的過程中那么頻繁地去執(zhí)行函數(shù)。這時(shí)候就用到防抖與節(jié)流。
案例 1:遠(yuǎn)程搜索時(shí)需要通過接口動(dòng)態(tài)的獲取數(shù)據(jù),若是每次用戶輸入都接口請(qǐng)求,是浪費(fèi)帶寬和性能的。
<Select :remote-method="remoteMethod"> <Option v-for="item in temoteList" :value="item.value" :key="item.id">{{item.label}}</Option> </Select> <script> function debounce(fn, wait) { let timeout = null return function () { if (timeout !== null) clearTimeout(timeout) timeout = setTimeout(fn, wait) } } export default { methods:{ remoteMethod:debounce(function (query) { // to do ... }, 200), } } <script>
案例 2:持續(xù)觸發(fā)scroll事件時(shí),并不立即執(zhí)行handle函數(shù),當(dāng) 1000 毫秒內(nèi)沒有觸發(fā)scroll事件時(shí),才會(huì)延時(shí)觸發(fā)一次handle函數(shù)。
function debounce(fn, wait) { let timeout = null return function () { if (timeout !== null) clearTimeout(timeout) timeout = setTimeout(fn, wait) } } function handle() { console.log(Math.random()) } window.addEventListener('scroll', debounce(handle, 1000))
默認(rèn)情況下,瀏覽器是同步加載js腳本,解析 html 過程中,遇到<script>標(biāo)簽就會(huì)停下來,等腳本下載、解析、執(zhí)行完后,再繼續(xù)向下解析渲染。
如果 js 文件體積比較大,下載時(shí)間就會(huì)很長(zhǎng),容易造成瀏覽器堵塞,瀏覽器頁(yè)面會(huì)呈現(xiàn)出“白屏”效果,用戶會(huì)感覺瀏覽器“卡死了”,沒有響應(yīng)。此時(shí),我們可以讓 js 腳本異步加載、執(zhí)行。
<script src="path/to/home.js" defer></script> <script src="path/to/home.js" async></script>
上面代碼中,<script>標(biāo)簽分別有defer和async屬性,瀏覽器識(shí)別到這 2 個(gè)屬性時(shí) js 就會(huì)異步加載。也就是說,瀏覽器不會(huì)等待這個(gè)腳本下載、執(zhí)行完畢后再向后執(zhí)行,而是直接繼續(xù)向后執(zhí)行
defer 與 async 區(qū)別:
defer:DOM 結(jié)構(gòu)完全生成,以及其他腳本執(zhí)行完成,才會(huì)執(zhí)行(渲染完再執(zhí)行)。有多個(gè)defer腳本時(shí),會(huì)按照頁(yè)面出現(xiàn)的順序依次加載、執(zhí)行。
async:一旦下載完成,渲染引擎就會(huì)中斷渲染,執(zhí)行這個(gè)腳本以后,再繼續(xù)渲染(下載完就執(zhí)行)。有多個(gè)async腳本時(shí),不能保證按照頁(yè)面出現(xiàn)順序加載、執(zhí)行
上述就是小編為大家分享的如何優(yōu)化Javascript前端代碼了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。