console.log(event)

<div class="ctn">
  <span class="inner">请点击这里</span>
</div>
1
2
3
var div = document.querySelector('.ctn')
div.onclick = function (evt) {
  console.log(evt)
  console.log(evt.currentTarget)
}
1
2
3
4
5

运行上述代码,会发现,

console.log(evt)打印出来的对象里currentTargetnull

console.log(evt.currentTarget)打印出来的是外层的div

这里的疑问是,为什么console.log(evt)console.log(evt.currentTarget)的结果不一样?

event 对象

var div = document.querySelector('.ctn')
var span = document.querySelector('.inner')
var event

span.onclick = function (evt) {
  event = evt
}
div.onclick = function (evt) {
  console.log(event === evt)  // true
}
1
2
3
4
5
6
7
8
9
10

运行以上代码,结果是为true,说明随着事件冒泡,event对象始终未变,变的是event对象里的属性。以currentTarget属性为例,在divclick事件处理函数里,event.currentTargetdiv,在spanclick事件处理函数里,event.currentTargetspan

console.log()

为了解开上面的疑问,先在浏览器控制台连续输入以下代码,最后按下 enter 查看打印出的值。

> var a = {}
  console.log(a)
  a.x = 2
1
2
3

实验结果

结果发现,即使console.log(a)在前,a.x = 2赋值在后,但是展开打印出来的 Obejct,发现值为{ x: 2 }

这是怎么回事呢?

让我们继续做实验来寻找原因:分别在浏览器控制台里输入以下两组代码,观察结果。

// 第一组
> var a = {}
  console.log(a)  // 输入此行后,按 enter 键(但是不展开打印出的对象),继续进行下面的输入
> a.x = 2  // 输入此行后,展开打印的对象,查看结果
1
2
3
4

第一组结果

// 第二组
> var a = {}
  console.log(a)  // 输入此行后,按 enter 键并且展开打印出的对象后查看结果,最后继续进行下面的输入
> a.x = 2

1
2
3
4
5

第二组结果

以上两组代码完全相同,只是展开打印对象的时机不同:

  • 第一组:在console.log(a)输入后按 enter 键,在a.x = 2输入后,展开打印出的对象
  • 第二组:在console.log(a)输入后按 enter 键,并展开打印出的对象,最后输入a.x = 2

通过以上两组结果的对比,我们做出猜想:通过console.log()打印对象,展开对象时,获取的是该对象在当时的一个快照。

解疑

结合以上的基础,就可以解释为什么console.log(evt)console.log(evt.currentTarget)的结果不一样了。

首先,事件冒泡到div元素时,click事件处理函数进行处理,此时event.currentTarget的值即为div

其次,在div元素的click事件处理函数里console.log(evt),在我们在控制台展开event对象时,冒泡已经结束,此时event对象的currentTargetnull,我们获取的是冒泡结束时的event对象的快照,因此evt对象里的currentTargetnull

如何隐藏 console.log 打印信息时的源文件名称和行号?

Reference: