試命令速查:Console API與命令行API實(shí)戰(zhàn)手冊)
我一直覺得Chrome 控制臺Console是前端開發(fā)里最值得花時(shí)間摸透的工具。很多人對它的印象停留在“看報(bào)錯(cuò)、點(diǎn)一下元素、跑兩行小腳本”但如果你把它當(dāng)成一個(gè)完整的調(diào)試命令行來用會(huì)發(fā)現(xiàn)里面藏著一整套 API 和快捷命令從選擇元素、監(jiān)聽函數(shù)、查看事件綁定到性能計(jì)時(shí)和斷點(diǎn)設(shè)置幾乎能覆蓋日常排查的絕大部分需求。這篇文章可以當(dāng)作一份通用版的 Console 命令速查文檔適合前端開發(fā)者、爬蟲調(diào)試人員以及對瀏覽器工具感興趣的產(chǎn)品和技術(shù)同學(xué)。我盡量把每條命令的用法、適用場景和容易踩的坑一起寫進(jìn)去爭取讓新手看完能直接上手老手也能翻到一些平時(shí)沒注意到的細(xì)節(jié)。1. 打開控制臺之前先搞清 Console 對象與命令行 API 的關(guān)系1.1 三種打開方式和最容易被忽略的兩個(gè)設(shè)置打開控制臺這件事聽起來沒什么好講的但不同場景下效率差異很大。Windows 和 Linux 下可以用 CtrlShiftJ 直接進(jìn)入 Console 面板macOS 上是 CommandOptionJ按 F12 打開開發(fā)者工具后再切到 Console 也完全沒問題。我個(gè)人習(xí)慣用快捷鍵直達(dá)因?yàn)檎{(diào)試時(shí)往往要反復(fù)切換 Elements、Sources、Network 面板每次都拿鼠標(biāo)點(diǎn)一遍真的很浪費(fèi)時(shí)間。進(jìn)入控制臺之后有兩處設(shè)置建議根據(jù)場景調(diào)整。第一處是日志級別過濾Console 默認(rèn)會(huì)把 Verbose詳細(xì)級別的日志折疊起來如果你想看console.debug()的輸出需要把日志級別切到 Verbose否則大概率會(huì)以為自己的打印語句沒生效。第二處是“Selected context only”如果你的頁面里有 iframe、擴(kuò)展腳本或者 service worker 在輸出日志Consonle 會(huì)很吵勾選這個(gè)選項(xiàng)可以只看當(dāng)前執(zhí)行上下文的內(nèi)容排查問題的時(shí)候干凈很多。1.2 Console 對象與命令行 API 的邊界這是很多人搞混的第一個(gè)點(diǎn)。console.log()、console.table()、console.time()這一系列屬于 Console API本質(zhì)是console對象上的方法寫在頁面代碼里一樣能執(zhí)行。而$_、$0、debug()、monitor()、copy()這些屬于命令行 API它們是 DevTools 注入到當(dāng)前執(zhí)行環(huán)境里的工具函數(shù)只存在于控制臺交互上下文頁面腳本里訪問不到。理解這個(gè)區(qū)別很重要。比如你在控制臺里輸入$0能拿到 Elements 面板當(dāng)前選中的元素但你不能把$0寫進(jìn)項(xiàng)目代碼里上線之后ReferenceError直接砸臉。反過來console對象上的方法可以被代碼覆蓋和改寫而命令行 API 通常不太容易受頁面腳本影響。調(diào)試的時(shí)候遇到“為什么這個(gè)函數(shù)在頁面上沒定義、在控制臺里卻能執(zhí)行”這類問題十有八九就是觸到了這個(gè)邊界。另一個(gè)容易被忽略的點(diǎn)是控制臺本質(zhì)上是一個(gè) REPL 環(huán)境你輸入的每一行都會(huì)先被 JavaScript 引擎執(zhí)行然后再把結(jié)果格式化輸出。所以像document.querySelector這種表達(dá)式會(huì)顯示函數(shù)源碼而如果直接輸入document控制臺會(huì)把整個(gè)文檔對象折疊成一個(gè)可點(diǎn)擊的樹形結(jié)構(gòu)。這個(gè)“先執(zhí)行、再格式化”的機(jī)制是所有控制臺命令行為的基礎(chǔ)后面的很多命令都是在這個(gè)邏輯上展開的。2. 高頻命令速查從 $_ 到 $0-$4再到 $() 與 $$()2.1 $_重復(fù)使用上一個(gè)計(jì)算結(jié)果$_是控制臺里非常實(shí)用的快捷變量它永遠(yuǎn)保存著上一個(gè)表達(dá)式的執(zhí)行結(jié)果。比如你在控制臺輸入1 2回車后得到 3此時(shí)輸入$_ * 4控制臺會(huì)直接返回 12。在計(jì)算嵌套數(shù)據(jù)、臨時(shí)修改某個(gè)值時(shí)這個(gè)變量能省掉很多重復(fù)輸入的功夫。實(shí)際用的時(shí)候有幾個(gè)細(xì)節(jié)要注意。$_保存的是最近一次表達(dá)式的結(jié)果如果你中間執(zhí)行了某個(gè)返回undefined的語句$_就被覆蓋成undefined了。另外在監(jiān)聽器里用$_還可能踩到坑比如你先執(zhí)行了一個(gè)異步操作然后又去讀$_拿到的不一定是預(yù)期的中間值。所以我的習(xí)慣是$_適合臨時(shí)交互不適合寫多步驟腳本復(fù)雜的中間值老老實(shí)實(shí)賦給自定義變量更穩(wěn)。2.2 $0-$4直接引用 Elements 面板選中的元素$0到$4是一組歷史引用$0返回 Elements 面板里當(dāng)前選中的元素$1返回上一次選中的元素依此類推總共保留最近五次選擇記錄。這個(gè)功能配合 Elements 面板使用堪稱神器先在頁面上右鍵“檢查”選中一個(gè)按鈕然后切到 Console 輸入$0.textContent馬上就能看到按鈕里的文案輸入$0.offsetParent能快速判斷它被哪個(gè)父級定位容器約束。我經(jīng)常用$0做“先選中、后操作”的調(diào)試流程。比如懷疑某個(gè)元素的樣式不對先在 Elements 里選中它再到 Console 里執(zhí)行$0.style.outline 2px solid red瞬間畫出邊框確認(rèn)邊界。如果發(fā)現(xiàn)改錯(cuò)了還能從$1、$2里找回之前選過的元素不需要跳回面板重新點(diǎn)選。唯一要注意的是這些引用只在當(dāng)前 DevTools 會(huì)話內(nèi)有效刷新頁面之后引用鏈會(huì)清空$0會(huì)變成undefined。2.3 $() 與 $$()選擇器函數(shù)的便捷替代$()是document.querySelector()的簡寫$$()是document.querySelectorAll()的簡寫但$$()返回的是數(shù)組不是 NodeList所以可以直接用map()、filter()、forEach()這些數(shù)組方法。舉個(gè)例子我想快速拿到頁面里所有外鏈的域名輸入$$(a[href^http]).map(a new URL(a.href).hostname)回車之后立刻能看到去重的域名列表。這在爬蟲調(diào)試和頁面結(jié)構(gòu)分析場景里特別順手不需要打開一個(gè)臨時(shí)編輯器寫循環(huán)、再粘貼回控制臺執(zhí)行。這里有一個(gè)經(jīng)典沖突如果頁面本身引入了 jQuery$這個(gè)標(biāo)識符會(huì)被 jQuery 占用控制臺里的$()可能就變成 jQuery 的選擇器了。遇到這種情況可以直接用document.querySelector()來兜底或者把函數(shù)重命名一下再使用比如const $ document.querySelector.bind(document)不過要注意在某些版本的 DevTools 里內(nèi)置$()和頁面全局$是會(huì)互相覆蓋的具體行為跟 DevTools 版本和頁面加載時(shí)機(jī)有關(guān)。我建議在團(tuán)隊(duì)項(xiàng)目里統(tǒng)一約定調(diào)試時(shí)優(yōu)先用$$()和document.querySelector避免被頁面環(huán)境干擾。2.4 高頻命令速查小抄為了方便日常翻閱我匯總了一張速查表覆蓋本文后面會(huì)展開講的一部分核心命令命令作用示例$_引用上一個(gè)表達(dá)式的結(jié)果$_$0引用 Elements 面板當(dāng)前選中的元素$0.style.color #f60$()querySelector的簡寫$(.nav).innerHTML$$()querySelectorAll的數(shù)組版簡寫$$(img).length$x()用 XPath 選擇元素$x(//div[classitem])copy()把內(nèi)容復(fù)制到剪貼板copy(document.title)clear()清空控制臺輸出clear()這里面$x()在 XPath 場景下很有用尤其是嵌套層級深的頁面結(jié)構(gòu)用 XPath 比 CSS 選擇器更靈活。但日常調(diào)試用 CSS 選擇器居多XPath 當(dāng)成補(bǔ)充工具記住就可以了。3. console.* 家族從 log 到 table 的完整用法3.1 log、info、warn、error、debug 的分級輸出console.log()是最基礎(chǔ)的輸出方法但實(shí)際項(xiàng)目里我很少單獨(dú)用log。更合理的做法是讓不同類型的消息走不同的級別普通信息用console.info()警告用console.warn()錯(cuò)誤用console.error()調(diào)試細(xì)節(jié)用console.debug()。這樣做的直接好處是控制臺自帶濾鏡可以把日志按級別過濾線上環(huán)境里warn和error會(huì)高亮顯示一眼就能抓到重點(diǎn)。你可能會(huì)問console.info()和console.log()的輸出樣式看起來幾乎一樣有必要區(qū)分嗎有。DevTools 的日志級別不僅僅影響顯示樣式還會(huì)影響性能監(jiān)控、錯(cuò)誤上報(bào)工具的過濾邏輯。很多團(tuán)隊(duì)的錯(cuò)誤監(jiān)控腳本會(huì)自動(dòng)捕獲console.error()的輸出如果你所有日志都一律用log后續(xù)想按級別篩數(shù)據(jù)就無從下手了。一個(gè)小坑console.debug()輸出在默認(rèn)情況下是不顯示的必須把日志級別切到 Verbose 才能看到。如果你在調(diào)試時(shí)“明明寫了debug卻找不到輸出”先別查代碼檢查一下控制臺的日志級別下拉菜單很大概率就是被過濾掉了。3.2 格式化輸出與 %c 樣式魔法console.log()支持類似 C 語言的格式化占位符常用的有%s字符串、%d整數(shù)、%o對象可展開的 DOM 對象、%O對象普通 JS 對象。比如console.log(%s %d %s, 訂單編號, 1024, 已支付)這個(gè)寫法的優(yōu)勢在于打印結(jié)構(gòu)復(fù)雜的字符串時(shí)不需要做一堆變量拼接讀起來也干凈。不過我想重點(diǎn)說的是%c占位符它后面的字符串會(huì)被當(dāng)成 CSS 樣式應(yīng)用到整條日志上console.log(%c訂單創(chuàng)建失敗, color: #fff; background: #e74c3c; padding: 4px 8px; border-radius: 4px; font-size: 14px;)這條日志打印出來是白字紅底的徽章樣式在大量日志輸出里極其醒目。我在團(tuán)隊(duì)的調(diào)試規(guī)范里推薦過這種做法錯(cuò)誤統(tǒng)一用紅底白字%c前綴警告用黃底黑字普通日志不加樣式。配合日志級別過濾基本上不用盯著屏幕找半天。3.3 console.table 與 console.dir從對象到表格console.table()是我最常用的輸出工具之一。當(dāng)你有一組結(jié)構(gòu)相似的對象時(shí)用table打印出來是一個(gè)可排序的表格視覺上比一堆折起來的大對象清晰太多。比如console.table([ { name: 張三, age: 24, city: 上海 }, { name: 李四, age: 30, city: 北京 } ])如果對象里有大量不需要展示的字段還可以傳第二個(gè)參數(shù)指定列console.table(list, [name, age])console.dir()則是把對象以樹形結(jié)構(gòu)展開顯示。最常見的用法是打印 DOM 元素console.log(document.body)顯示的是 HTML 標(biāo)簽結(jié)構(gòu)而console.dir(document.body)顯示的是這個(gè)元素的屬性和方法列表包括clientWidth、scrollHeight、dataset這些你需要的信息。想快速了解一個(gè) DOM 節(jié)點(diǎn)有什么屬性時(shí)dir遠(yuǎn)比log好用。3.4 計(jì)時(shí)、分組、計(jì)數(shù)、斷言與堆棧這幾個(gè)方法比較“小而美”但每個(gè)都有明確的使用場景。console.time()和console.timeEnd()是一對計(jì)時(shí)器括號里的標(biāo)簽是同一個(gè)字符串時(shí)才會(huì)正確結(jié)束并打印耗時(shí)。比如console.time(數(shù)組排序耗時(shí)) arr.sort() console.timeEnd(數(shù)組排序耗時(shí))要注意time和timeEnd的標(biāo)簽必須完全一致拼寫錯(cuò)一點(diǎn)就會(huì)得到一條警告信息而無法正常輸出。標(biāo)簽重復(fù)使用時(shí)timeEnd會(huì)結(jié)束上一次未結(jié)束的同名計(jì)時(shí)器所以嵌套場景下盡量用語義化標(biāo)簽。console.count()用來統(tǒng)計(jì)同一段代碼的執(zhí)行次數(shù)適合確認(rèn)事件回調(diào)有沒有觸發(fā)、觸發(fā)了多少次。配合countReset()可以清零重新計(jì)數(shù)。console.group()和console.groupEnd()可以把一組日志折疊起來。業(yè)務(wù)邏輯比較復(fù)雜時(shí)把不同模塊的輸出歸組控制臺會(huì)清爽很多。groupCollapsed()則是默認(rèn)折疊的版本想看細(xì)節(jié)再點(diǎn)展開大型項(xiàng)目里實(shí)測很好用。console.assert()會(huì)在條件為假時(shí)打印一條錯(cuò)誤日志相當(dāng)于“斷言”。我調(diào)試接口數(shù)據(jù)時(shí)經(jīng)常用它c(diǎn)onsole.assert(user.age 18, 用戶年齡必須大于18當(dāng)前值, user.age)條件滿足時(shí)什么都不打印條件不滿足時(shí)直接紅字報(bào)錯(cuò)寫臨時(shí)校驗(yàn)邏輯很方便。最后是console.trace()它會(huì)在控制臺打印當(dāng)前的調(diào)用堆棧。排查“這個(gè)函數(shù)到底是被誰調(diào)進(jìn)來的”這類問題時(shí)在可疑函數(shù)里加一行console.trace()就能看到完整的調(diào)用鏈路不用去 Sources 面板手動(dòng)打斷點(diǎn)。4. 命令行 API 里容易被人忽略的老牌工具debug、monitor、getEventListeners4.1 debug 與 monitor給第三方函數(shù)“插樁”debug()命令可以在指定函數(shù)上自動(dòng)設(shè)置一個(gè)斷點(diǎn)函數(shù)執(zhí)行時(shí)就會(huì)停在入口處。用法是傳入函數(shù)本身或函數(shù)名比如debug(fetch)這樣頁面任何代碼調(diào)用fetch時(shí)都會(huì)在fetch入口斷住你可以在 Sources 面板里一步步看參數(shù)、走邏輯。不想繼續(xù)就執(zhí)行undebug(fetch)移除斷點(diǎn)。這個(gè)功能最妙的地方在于不管目標(biāo)函數(shù)是你自己寫的還是第三方庫里的只要能在全局作用域訪問到就能直接插樁。我曾經(jīng)用debug(HTMLElement.prototype.click)來排查一個(gè)“明明調(diào)用了 click 卻沒有觸發(fā)點(diǎn)擊事件”的問題斷住之后直接看到調(diào)用方傳進(jìn)來的上下文問題根源立刻就清楚了。monitor()和debug()類似但它是打印函數(shù)的每次調(diào)用參數(shù)和返回值而不是中斷執(zhí)行monitor(document.querySelector)之后每執(zhí)行一次document.querySelector(...)控制臺就會(huì)輸出一條記錄包含參數(shù)和返回結(jié)果。這種監(jiān)聽方式對確認(rèn)“某個(gè)函數(shù)有沒有被調(diào)用、被調(diào)用了幾次、每次都傳了什么”非常有幫助尤其適合定位“某個(gè)接口被無限重復(fù)請求”這類性能問題。用unmonitor()取消監(jiān)聽。4.2 getEventListeners查看元素綁了哪些事件getEventListeners()返回指定元素上注冊的所有事件監(jiān)聽器對象。比如選中一個(gè)按鈕后getEventListeners($0)輸出結(jié)果會(huì)按事件類型分組click字段下的數(shù)組里就是該事件注冊的所有處理函數(shù)。每個(gè)監(jiān)聽器對象里還能看到useCapture、passive等屬性排查事件是冒泡觸發(fā)還是捕獲觸發(fā)時(shí)非常直觀。這個(gè)命令的典型使用場景是“頁面有個(gè)按鈕點(diǎn)了沒反應(yīng)”。很多新人會(huì)直接去代碼里搜a(bǔ)ddEventListener但如果你用的是第三方組件庫事件綁定可能發(fā)生在庫的內(nèi)部搜半天搜不到。直接在控制臺getEventListeners($0).click看一下數(shù)組里到底有幾個(gè)處理函數(shù)每個(gè)函數(shù)的源碼是什么一下子就鎖定了范圍。如果監(jiān)聽器返回空對象說明這個(gè)元素根本沒有綁定對應(yīng)事件問題很可能出在事件委托或者別的元素上排查方向立刻就能調(diào)整。4.3 keys、values、copy、inspect、clear輔助操作一把梭keys()和values()分別返回對象的所有鍵名和鍵值數(shù)組。它們看起來和Object.keys()重復(fù)但妙處在于可以用在任意控制臺表達(dá)式上配合$_使用非常流暢const obj { name: test, level: 2 } keys(obj) values(obj)copy()會(huì)把內(nèi)容復(fù)制到系統(tǒng)剪貼板這個(gè)命令我要單獨(dú)夸一下。平時(shí)想把接口返回的大 JSON 復(fù)制到編輯器里手動(dòng)選中復(fù)制不僅費(fèi)勁還可能漏掉縮進(jìn)。直接copy(JSON.stringify(data, null, 2))然后去編輯器里粘貼格式完整、絕不丟內(nèi)容。配合fetch在控制臺里先獲取接口數(shù)據(jù)再用copy導(dǎo)出來整個(gè)鏈路不到五秒鐘。inspect()會(huì)跳轉(zhuǎn)到 Elements 面板并選中傳入的 DOM 元素。比如從一堆匹配div中篩選出第一個(gè)想看看它在頁面上的實(shí)際位置inspect($(div))clear()清空控制臺輸出。需要注意它和console.clear()的區(qū)別console.clear()是 Console API可以在代碼里調(diào)用clear()是命令行 API只能在控制臺交互里執(zhí)行。兩者效果一樣但頁面代碼里沒有clear()這個(gè)函數(shù)用錯(cuò)了會(huì)報(bào)錯(cuò)。5. 幾個(gè)真實(shí)的調(diào)試場景從找事件到查性能瓶頸5.1 場景按鈕點(diǎn)擊沒反應(yīng)先查監(jiān)聽器再?zèng)Q定是否打斷點(diǎn)有次接到一個(gè)反饋說頁面上某個(gè)“提交訂單”按鈕點(diǎn)擊沒有任何反應(yīng)。這種問題大多數(shù)時(shí)候不是按鈕沒綁定事件而是事件綁定了但執(zhí)行出錯(cuò)或者被某個(gè)外層元素?cái)r截了。我的排查鏈路是先在 Elements 面板選中按鈕切到 Console 執(zhí)行g(shù)etEventListeners($0)如果click數(shù)組是空的說明按鈕自身沒有綁定事件可能事件在父級委托或者按鈕被一層遮罩蓋住、壓根點(diǎn)不到。如果click數(shù)組里有多個(gè)處理函數(shù)逐個(gè)看函數(shù)源碼找到可疑的那一個(gè)然后debug($0.__clickHandler)這樣我就能在點(diǎn)擊按鈕時(shí)停在對應(yīng)函數(shù)入口按步執(zhí)行看哪一行拋異常。整套流程下來從發(fā)現(xiàn)問題到鎖定根因通常不會(huì)超過三分鐘。5.2 場景用一個(gè)函數(shù)找出頁面里的重復(fù)事件綁定有次排查一個(gè)性能問題發(fā)現(xiàn)某個(gè)列表項(xiàng)的點(diǎn)擊事件執(zhí)行次數(shù)成倍增長懷疑是事件被重復(fù)綁定了。直接在控制臺里寫一個(gè)小函數(shù)遍歷關(guān)鍵節(jié)點(diǎn)$$(.list-item).map(item ({ text: item.textContent.slice(0, 10), listeners: getEventListeners(item).click?.length || 0 }))$$()拿到所有列表項(xiàng)getEventListeners()統(tǒng)計(jì)每個(gè)項(xiàng)綁定的 click 監(jiān)聽器數(shù)量。輸出的表格一眼就能看出哪些項(xiàng)綁定了多個(gè)監(jiān)聽器順著那段代碼去找重復(fù)綁定的地方就非常快了。這種組合拳是控制臺命令的真正價(jià)值單個(gè)命令只能幫你做一件事組合起來能幫你快速做結(jié)構(gòu)化排查。5.3 場景監(jiān)控異步函數(shù)的調(diào)用頻率和參數(shù)另一個(gè)常見需求是“某個(gè)接口好像被頻繁調(diào)用每次參數(shù)都不一樣”。直接打斷點(diǎn)太煩因?yàn)榻涌诿棵肟赡苷{(diào)用幾十次。這時(shí)候monitor()就派上用場了monitor(fetch)然后什么都不用做正常操作頁面控制臺會(huì)持續(xù)輸出每次fetch的調(diào)用參數(shù)和返回值。打開控制臺觀察輸出頻率馬上就能判斷接口是不是在循環(huán)里被調(diào)用。如果是某個(gè)特定函數(shù)導(dǎo)致的可以換成monitor(axios.post)或者直接監(jiān)聽自定義業(yè)務(wù)函數(shù)。這種方法不侵入代碼、不打斷運(yùn)行流程非常適合線上環(huán)境的即時(shí)排查。5.4 場景計(jì)算一段渲染邏輯的實(shí)際耗時(shí)性能優(yōu)化時(shí)console.time()是最直接的計(jì)時(shí)手段。但要注意在控制臺里使用它和在代碼里使用有一點(diǎn)區(qū)別控制臺本身是異步執(zhí)行的可能無法捕捉到瀏覽器渲染管線之后的完整時(shí)間。如果需要更精確的數(shù)據(jù)建議配合performance.now()const start performance.now() // 在控制臺手動(dòng)觸發(fā)一段邏輯 console.log(耗時(shí), performance.now() - start, ms)這種原始的時(shí)間戳方式更適合控制臺交互場景因?yàn)樗灰蕾嘽onsole.time()內(nèi)部的事件循環(huán)機(jī)制結(jié)果更可靠。特別是在對比“兩種寫法哪種更快”的時(shí)候直接在控制臺跑幾輪、算平均值效果比憑感覺判斷好得多。6. 團(tuán)隊(duì)項(xiàng)目里關(guān)于 console 的幾個(gè)實(shí)踐問題6.1 把 console.log 從臨時(shí)工具變成團(tuán)隊(duì)規(guī)范很多項(xiàng)目里的console.log是臨時(shí)調(diào)試隨手寫的上線時(shí)要么忘記刪要么全刪掉下一次排查問題時(shí)又到處亂加。我見過比較成熟的團(tuán)隊(duì)會(huì)定一套簡單的打印規(guī)范業(yè)務(wù)入口和出口用console.info異常用console.error性能耗時(shí)統(tǒng)一用performance的標(biāo)記然后配合console.group把同一模塊的日志歸組。這樣開發(fā)環(huán)境和線上排查都舒服很多。另外我強(qiáng)烈建議在團(tuán)隊(duì)調(diào)試規(guī)范里引入%c樣式前綴。比如所有組件庫內(nèi)部調(diào)試日志統(tǒng)一用藍(lán)色前綴[Lib]業(yè)務(wù)日志用綠色前綴[Biz]錯(cuò)誤日志用紅底白字。這樣混合輸出的時(shí)候掃一眼顏色就能判斷日志屬于哪個(gè)體系不用每條都展開看。成本極低收益非常直接。6.2 生產(chǎn)環(huán)境還能不能留著 console 輸出這是團(tuán)隊(duì)項(xiàng)目里繞不開的問題。我的觀點(diǎn)是不是所有console都要?jiǎng)h而是要看輸出的內(nèi)容是否涉及敏感數(shù)據(jù)。像接口請求參數(shù)、用戶信息、內(nèi)部錯(cuò)誤對象這些在任何環(huán)境下都不應(yīng)該打印。對于無害的結(jié)構(gòu)化日志如果開發(fā)環(huán)境已經(jīng)夠用線上可以保留但要控制級別和數(shù)量避免日志量大到影響性能。如果公司項(xiàng)目里希望構(gòu)建產(chǎn)物完全去掉console可以借助構(gòu)建工具的配置。比如在打包壓縮階段把 console 相關(guān)語句移除配置思路是按環(huán)境區(qū)分只有生產(chǎn)環(huán)境才開啟移除。需要注意移除console不僅僅是刪幾行代碼的問題如果代碼里存在依賴console返回值或者把console傳給其他函數(shù)的寫法暴力移除可能導(dǎo)致運(yùn)行時(shí)報(bào)錯(cuò)。所以在做全局清理前先檢索一下項(xiàng)目里的console用法確認(rèn)都是獨(dú)立調(diào)用再去配置清理規(guī)則。6.3 用控制臺給前端函數(shù)做“單測”和渲染驗(yàn)證最后分享一個(gè)日常工作里的小玩法在控制臺里臨時(shí)粘貼一個(gè)函數(shù)定義然后立刻調(diào)用驗(yàn)證。比如我急著確認(rèn)某個(gè)時(shí)間格式化函數(shù)在不同邊界下是否正常function formatTime(t) { return t 10 ? 0 t : String(t) } [0, 5, 9, 10, 23].map(formatTime)控制臺直接輸出結(jié)果比反復(fù)刷新頁面、點(diǎn)擊操作要快得多。如果驗(yàn)證的是組件渲染邏輯可以先在控制臺改一個(gè)元素的關(guān)鍵樣式或文本再?zèng)Q定是不是要落代碼。這種“用小函數(shù)快速驗(yàn)證邏輯、再遷移到項(xiàng)目里”的做法能明顯減少提交代碼后發(fā)現(xiàn)低級 bug 的頻率。控制臺本質(zhì)上是瀏覽器自帶的一個(gè) JavaScript 運(yùn)行時(shí)用來做臨時(shí)實(shí)驗(yàn)、邊界值測試、數(shù)據(jù)篩選體驗(yàn)完全不輸給本地寫腳本跑一遍。