04Js面试题-函数this指向

156 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

一、this指向问题

  • 函数中的this指向函数执行时调用它的对象,若没有调用者则this=window

  • 下面一段代码中,在执行代码a();时,由于执行函数a时没有调用者,所以函数a的this=window,因此console.log.log(this.name);打印的时全局的变量name='windowName',console.log(this);打印的时全局对象window

image.png

  • 函数中的this指向的时直接调用它的对象,所以下面一段代码中,函数fn的this指向对象a,所以console.log(this.name);打印的是a.name,即'cherry'

image.png

  • 下面两段代码中,在函数fn执行时,都没有调用者,所以this=window,因此this.name=window.name='windowName'

image.png

image.png

二、改变this指向

  • 在下面的代码中,对象a的函数func2中的setTimeout函数由于没有调用者,它的this=window,但一般开发者是希望this指向对象a,有下文中的几种方法可以实现这个需求

image.png

(一)静态改变this指向

方法一:箭头函数

  • 箭头函数体内的this指向的是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
  • 因此,将setTimeout中的函数参数有匿名函数改为箭头函数,就可以让this指向a,因为该箭头函数所在的作用域是韩式func2,a.func2指向的对象就是a(作用域指向的对象)。该方法的代码实现如下:

image.png

方法二:使用变量保存指针(闭包)

  • 这种方法很好理解,就是将你想指向的对象保存到一个变量中,之后需要操作这个对象就只要使用这个变量
  • 这种方法利用了闭包,闭包就是能够读取其他函数内部变量的函数,也可以简单的理解成定义在一个函数内部的函数。根据js语言特有的“链式作用”结构(chain scope),子对象会一级一级地向上寻找所有的父对象的变量。父对象所有的变量对子对象都是可见的,反之不成立,这就是实现闭包的原理。在下面的代码中,setTimeout()就是子对象,函数func2就是父对象,根据闭包的特点子对象可以访问到父对象的变量_this
  • 关于闭包,还有一个用处就是它会让父对象的变量值始终保持在内存中,不会在父对象函数调用后被自动清除。这是因为子函数被赋给了一个全局变量,这就导致子函数始终在内存中,而子函数的存在依赖于父函数,所有父函数也就始终在内存中,不会在调用结束后被垃圾回收机制回收

image.png

(二)动态改变this指向

方法三:call/apply/bind

  • call方法:会让函数立即执行
  • apply方法:会让函数立即执行
  • bind方法:会绑定作用域,但是不立即执行

image.png

三、手动实现动态绑定this指向方法

  • 下面的代码时对call方法的实现,apply方法和bind方法的实现时类似的,只要更改参数的传入方式和是否让函数立即执行即可

image.png