Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
一、this指向问题
-
函数中的this指向函数执行时调用它的对象,若没有调用者则this=window
-
下面一段代码中,在执行代码
a();时,由于执行函数a时没有调用者,所以函数a的this=window,因此console.log.log(this.name);打印的时全局的变量name='windowName',console.log(this);打印的时全局对象window
- 函数中的this指向的时直接调用它的对象,所以下面一段代码中,函数fn的this指向对象a,所以
console.log(this.name);打印的是a.name,即'cherry'
- 下面两段代码中,在函数fn执行时,都没有调用者,所以this=window,因此
this.name=window.name='windowName'
二、改变this指向
- 在下面的代码中,对象a的函数func2中的setTimeout函数由于没有调用者,它的this=window,但一般开发者是希望this指向对象a,有下文中的几种方法可以实现这个需求
(一)静态改变this指向
方法一:箭头函数
- 箭头函数体内的this指向的是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
- 因此,将setTimeout中的函数参数有匿名函数改为箭头函数,就可以让this指向a,因为该箭头函数所在的作用域是韩式func2,a.func2指向的对象就是a(作用域指向的对象)。该方法的代码实现如下:
方法二:使用变量保存指针(闭包)
- 这种方法很好理解,就是将你想指向的对象保存到一个变量中,之后需要操作这个对象就只要使用这个变量
- 这种方法利用了闭包,闭包就是能够读取其他函数内部变量的函数,也可以简单的理解成定义在一个函数内部的函数。根据js语言特有的“链式作用”结构(chain scope),子对象会一级一级地向上寻找所有的父对象的变量。父对象所有的变量对子对象都是可见的,反之不成立,这就是实现闭包的原理。在下面的代码中,setTimeout()就是子对象,函数func2就是父对象,根据闭包的特点子对象可以访问到父对象的变量
_this - 关于闭包,还有一个用处就是它会让父对象的变量值始终保持在内存中,不会在父对象函数调用后被自动清除。这是因为子函数被赋给了一个全局变量,这就导致子函数始终在内存中,而子函数的存在依赖于父函数,所有父函数也就始终在内存中,不会在调用结束后被垃圾回收机制回收
(二)动态改变this指向
方法三:call/apply/bind
- call方法:会让函数立即执行
- apply方法:会让函数立即执行
- bind方法:会绑定作用域,但是不立即执行
三、手动实现动态绑定this指向方法
- 下面的代码时对call方法的实现,apply方法和bind方法的实现时类似的,只要更改参数的传入方式和是否让函数立即执行即可