除了可以在JavaScript 执行的Console API 外,Console 还提供了一些Debug 专用的Function,每一个都身怀绝技。
阅读本篇文章时建议搭配Demo页面Console - Utilities,效果更佳。
Console Utility Functions
还记得笔者第一次看到这些Function时特别兴奋,直接写在自己的程式码中,想当然是跳出了各种Uncaught ReferenceError: xxx is not defined。
$_
会 储 存 的 执 行 结 果 , 在 C o n s o l e 测 试 J a v a S c r i p t 行 为 的 时 候 通 常 都 会 逐 步 确 认 , 正 是 使 用 _会储存的执行结果,在Console测试JavaScript行为的时候通常都会逐步确认,正是使用 会储存的执行结果,在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.querySelector和document.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 的小撇步。