(Day-16) this 介绍上 - this 的指向

前言

不论是学习或是开发时,我们容易被 this 的指向搞的头昏眼花,接下来会花两个篇幅介绍 this 指向。

也因为 this 容易把人搞乱这边先列出影响 this 指向的方法:

  • 简易呼叫 ( simple call)
  • 物件函式呼叫
  • addEventListener() 监听事件触发的函式
  • bind ﹑apply 、 call 绑定方法
  • 严格模式
  • new 建构式
  • 箭头函式

本章节会先介绍上面 简易呼叫、物件函式呼叫 ,addEventListener() 监听事件触发的函式这三个。

bind ﹑apply 、 call 绑定方法、严格模式 下篇则会说明这两组状况,剩余的 new 建构式 、箭头函式 则会到他们各自章节介绍。

简易呼叫 ( simple call)

先来看看指向全域的(window) 的 this 写法:

var name = 'Ryder'
function showName() {
  console.log(this.name) 
}
showName()

这边直接使用 showName() 这种直接呼叫函式的方法,这种直接呼叫函式的方法我们称做 简易呼叫 ,只要是由简易呼叫触发的函式,他当中的 this 一律指向 window

可以看到范例中确实会显示 Ryder ,其实范例中 this 指向的是 window

顺带一题我们常用的 forEach()filter() 中的 callback function ,他也是属於 简易呼叫 ,例如:

var name = 'Ryder'
var array = [1,2,3]
array.forEach(function(){
  console.log(this.name) // Ryder * 3
})

array.filter(function(){
  console.log(this.name) // Ryder * 3
})



物件函式呼叫

再来看看 this 指向物件的写法:

var name = 'Ryder';
var obj = {
  name: 'Jack',
  showName() {
    console.log(this.name) // Jack
  },
}
obj.showName()

这个范例中 this 指向的是 obj 这个物件本身,关於物件函式的 this 指向有一个小撇步, this 指向的位置就是,呼叫函式 xxx() 的上一层物件 ,如图:

在使用另一个多层物件来看看结果是否一致

var name = 'Ryder';
var obj1 = {
  name: 'Jack',
  obj2: {
    name: 'Alice',
    showName() {
      console.log(this.name) //Alice
    },
  }
}
obj1.obj2.showName()

在根据小撇步 this 会是 showName() 的上一层物件,图片就会是

而答案也是正确的,范例中的 this 指向的会是 obj2 ,因此这个范例显示 'Alice'

addEventListener() 监听事件触发的函式

function eventFn(){
  console.log(this) // DOM
}
const box = document.querySelector('.box')
box.addEventListener('click', eventFn)

当我们使用 addEventListener 配合 clickmouseover 等等事件触发的函式,他里面的 this 会是指向触发事件的 DOM 本身,比如这个范例的点击 box 时, this 就会是 class="box" 的 DOM 元素:

但要注意的是,这个 DOM 指向是 addEventListener() 特有的, 我们如果改成早期的 onclick 写法,则又会发现 this 指向的是 window (全域) 。

这个范例,完整程序码可以参考 codepen :https://codepen.io/rider159159/pen/JjJrgjK

延伸范例

看到这里你可能会想说 this 的指向好像并不困难,上述都是建立在程序码拆开来说的情况,接下来就以上面观念,举出一些容易让人觉的混乱例子,并且在一一说明。

范例一:

var name = 'Ryder'
var obj = {
  name :'Jack',
  showName() {
    name = 'Alice'
    console.log(this.name)
  },
}

var a = obj.showName
a() 

结果会是 Alice 这是因为 obj.showName 赋值给变数 a 时,并没有使用 () 呼叫 ,因此是将 showName 这个函式的整个内容,赋值到 a 变数上,接者呼叫 a() 来执行原本是 showName 函式中的语法,因此这边 a() 是 简易呼叫,所以 this 会指向 window

但是一执行 a() ,函式中 name = 'Alice' 这段语法就会将全域 name 的值替换成 Alice ,可以在浏览器打上 name 来查看全域的 name 是否被替换。

范例二:

var name = 'Ryder'
var obj = {
  name: 'Jack',
  showName() {
    name = 'Alice'
    console.log(this.name)
  },
}

var a = obj.showName()
a

这个结果就会是 Jack ,虽然有把 obj.showName() 赋值到变数 a ,但这边还是由 obj.showName() 来呼叫 showName() 函式,因此这个函式的状况仍然如下图,自然 this 的指向就会是 obj

范例三:

function eventFn(){
  var name = 'Jack'
  array.forEach(function(){
    console.log(this.name)
   })
}

var name = 'Ryder'
var array = [1,2,3]
var box = document.querySelector('.box')
box.addEventListener('click', eventFn)

点击 box 时会显示?

结果会是显示三次的 Ryder ,虽然 eventFn 是由事件触发,但 this 所在的 funciotnforEach 的 callback function ,而 callback function 也是属於简易呼叫的一种,因此 this 指向的是 window ,所以显示全域的 Ryder

参考文献


<<:  ActionScript 语言和你 SAY HELLO!!

>>:  第 1 天 大闲人降生

DAY19-JAVA的抽象类别(2)

利用父类别的变数来存取子类别物件的成员 public class Test{ public stat...

[Day 29] 利用CreateML训练的模型判断情绪(下)

昨天我们已经做出用CreateML训练的模型来判断情绪的app,今天就要来展示我们的成果,那这边设...

Windows Event探索练习--开关机和Office的大小事件

今天要来研究一些常见的事件,来看看有那些东西会被系统纪录下来,他们的意义又是什麽。 笔者查了查发现不...

Day8-Go阵列Array

前言 阵列是一种资料结构,里面装载的资料必须是同性质的,不能同时装载着字串又装载着整数,且建立後阵列...

第 53 天 - 研究 shell 解释器 - for each 批量停用没有用到服务

今天进度 : 鸟哥的 Linux 私房菜 -- 区域网路的环境设定 测试开放外网的时候,使用 net...