iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 8
1
Modern Web

你所不知道的各種前端 Debug 技巧系列 第 8

[Day 08] Console - Utilities Function

除了可以在 JavaScript 執行的 Console API 外,Console 還提供了一些 Debug 專用的 Function,每一個都身懷絕技。

閱讀本篇文章時建議搭配 Demo 頁面 Console - Utilities,效果更佳。

Console Utility Functions

還記得筆者第一次看到這些 Function 時特別興奮,直接寫在自己的程式碼中,想當然是跳出了各種 Uncaught ReferenceError: xxx is not defined

 

$_

$_ 會儲存的執行結果,在 Console 測試 JavaScript 行為的時候通常都會逐步確認,正是使用 $_ 的好時機:

 
用到很多不能 Chain 的 Function 時能利用 $_ 來避免游標來回修改:

順帶一提,未來也有可能出現 Pipeline operator 來做到任意 Function chaining ,提升可讀性或避免需要修改內建 Prototypes。

let a;
a = 1
  |> ((n) => add(n, 5))
  |> double;

console.log(a); // 12

 

$, $$

$(selector[, element]), $$(selector[, element])

$$$ 分別就是 document.querySelectordocument.querySelectorAll 的縮寫,來源就是大家熟知的 JQuery。

第二個參數可以放入起始的元素。搭配 $0 就可以先 Inspect 一個元素,再從它開始搜尋。

$('.btn', $0)

筆者常用 $$ 來快速測試一些行為,例如印出個人 GitHub 頁面的所有 Repository 名稱:

不過如果已經引入套件如 JQuery 為 $ 的話,還是會正常執行JQuery。

 

debug

debug(function)

參數為一個 Function,只要執行到該 Function 就會觸發 Debugger,可以用 undebug(fn) 來取消:

function a() {
  console.log(1);
}

debug(a);
// undebug(a);

其效果相當於:

function a() {
  console.log(1);
}
a = (function() {
  const origin = a;
  return function() {
    debugger;
    origin();
  }
})();

關於斷點(Breakpoints)的使用,會在之後關於 Sources 的文章有更詳細的解釋。

 

monitor

monitor(function)

用法和 debug 很像,monitor 的 Function 被執行時會印出 Function 名稱和參數,

可用 unmonitor(function) 來停止,不過無法用在 Arrow function,需要監聽 Arrow function 的執行就只能手動覆寫了。

 

monitorEvents

monitorEvents(element[, eventType])

可以在監聽並印出元素的特定事件,比較特別的是除了能監聽單一事件,還能監聽事件類型,例如印出 window 的點擊事件和所有 touch 類別的事件:

效果和以下 JavaScript 相同:

window.addEventListener('click', console.log)
window.addEventListener('touchstart', console.log)
window.addEventListener('touchmove', console.log)
window.addEventListener('touchend', console.log)
window.addEventListener('touchcancel', console.log)

另外可用 unmonitorEvents(element[, eventType]) 來停止監聽。

 

getEventListeners

getEventListeners(element)

印出已註冊在元素上的監聽器,以剛剛的例子來說,輸入 monitorEvents(element) 後再輸入 getEventListeners(element) 就會看到所有事件都被註冊了一輪:

展開的話可以看到監聽器的各種屬性:

  • listener -- 觸發事件執行的 Function
  • once -- 該監聽器只會觸發一次
  • passive -- 不能執行 event.preventDefault(),常用在提升監聽器的效能如 scroll
  • type -- 監聽事件類型
  • useCapture -- 監聽器會在 Capture 階段攔截事件

上述的屬性都是能在執行 addEventListener 時提供的參數,記得在 removeEventListener 時也要填入相同的參數才能移除監聽器。

const options: {
  capture: true,
  passive: true,
  once: false
}
window.addEventListener('click', console.log, options);
// window.removeEventListener('click', console.log, options);

 

queryObjects

queryObjects(object)

官方文件說明是返回 Constructor 產生的所有 Instances,不過筆者認為應該解釋為:印出所有原型鍊包含該原型的物件。

可以看到以 a 為原型建立的 b 也會出現在 queryObjects(A) 的結果中。

另外由於 queryObjects 並不會直接 return 陣列,而是過了一下才印出來,這邊利用右鍵 > Store as global variable 來把陣列放進變數 temp1
 

copy

copy(object)

copy 能夠把 DOM、物件複製到剪貼簿,例如筆者有時候會用 copy 把物件轉為 JSON,貼到對話框來討論 API Spec,或是用 Console 來快速建立、修改假資料。

貼心的加入縮排了呢!

 

keys, values

keys(object), values(object)

印出物件自身的所有 key 或 value,效果和 Object.keys(object)Object.values(object) 相同,為何強調自身呢?如果是用 in 來遍歷物件的各個屬性,就會把 Protoype 鍊上的屬性全都拿出來跑一遍:

const object = Object.create({ foo: 1});
object.bar = 2;
for (let key in object) {
  console.log(key)
}
// bar
// foo

除了是自身的 key,還要 enumerable

如果想要確認屬性是否是定義在物件自身可以用 Object.prototype.hasOwnProperty

for (let key in object) {
  if (Object.prototype.hasOwnProperty.call(object, key)) {
    console.log(key);
  }
}
// bar

至於為什麼不用 object.hasWonProperty(key),請參考下方程式碼:

const object1 = {
  hasOwnProperty: function() {
    return false;
  },
};
const object2 = Object.create(null);

object1.key = 'key';
object2.key = 'key';

object1.hasOwnProperty('key'); // ?
object2.hasOwnProperty('key'); // ?

 

clear

clear()

雖然按下左上角的 ? 就能把 Console 清乾淨,但筆者還是習慣用 clear(),就像在 terminal 輸入 clear 一樣。

注意在 Preserve log 開啟的狀況下 clear 並不會清空 Console。

 

小結

終於講完了 Console Utility Functions,明天將會繼續講一些在 Console 內執行 JavaScript 的小撇步。


上一篇
[Day 07] Console - API
下一篇
[Day 09] Console - Run JavaScript
系列文
你所不知道的各種前端 Debug 技巧30

尚未有邦友留言

立即登入留言