JavaScript学习总结之函数的this指向

前言

继上篇匿名函数的this指向问题后,续写和总结JavaScript中函数的this指向问题,下文将介绍有关函数this绑定的四条规则。segmentfault

调用位置

关于函数的this,经常有句话,叫作谁调用就指向谁。简单来讲this的指向跟函数的调用位置紧密相关,要想知道函数调用时this到底引用了什么,就应该明确函数的调用位置。通常来讲须要经过函数的调用栈来判断来分析出函数真正的调用位置,具体怎么分析呢?除了目测代码(就是盯着看-。-)外,还也能够借用浏览器的开发者工具(debug工具),去推断目标函数究竟是在哪里调用的,这样才能更准确的知晓this的指向。好比下面这段代码:浏览器

function foo() {
      console.log('foo')
    }

    function bar() {
      console.log('bar')
      foo()
    }

    bar()

要想知道foo函数是由谁调用的,就能够在浏览器中打开调试工具,在foo函数中的第一行打一个断点,找到函数的调用栈,而后再找到栈中的第二个元素,这就是真正的调用位置。以下图所示:
QQ图片20200516152301.png
从浏览器的调试工具能够找到foo函数的真正调用位置。app

默认绑定

默认绑定规则通常用于函数独立调用时。如下面的代码为例:函数

var a = 2
    function foo() {
      var a = 3
      console.log(this.a)
    }

    foo() // 2

输出结果为2。由于foo函数调用时处于全局环境下(这里是window),查看一下浏览器中的调用栈:工具

pic1.png

调用栈中只有foo函数一个元素,说明调用者就是当前的全局环境window,因此这里的this指向的就是window,由于最外部的a一开始是最为window.a 声明并赋值的,因此能够理解为this = window; this.a = 2。比较特殊的一点就是,若是在foo函数内部采用了严格模式,那么this就会绑定到undefined:学习

var a = 2
    function foo() {
      'use strict'
      var a = 3
      console.log(this.a)
    }

    foo() //`//Cannot read property 'a' of undefined`

隐式绑定

举以下代码为例:优化

var a = 2
    function foo() {
      console.log(this.a)
    }

    var obj1 = {
      a:3,
      foo: foo
    }

    obj.foo() //3

输出结果为3,说明这里的this指向的是obj1,为何再也不是指向全局环境了呢。在这里就要考虑到调用位置是否存在上下文对象,或者说是否被某个对象拥有或包含。在上述的代码中,foo函数的引用被赋给了obj1的foo属性obj1.foo = foo, 而且在foo函数被调用时,它的前面也加上了对obj1的引用。此时,当函数引用有上下文对象时,隐式绑定规则就会将函数中的this绑定到这个上下文对象,这里的上下文对象就是obj1。
其实在理解上下文对象时,我的以为不用那么抽象,它无非就是一个不肯定的代名词,简单来讲你以为它是什么,那它就是什么(-。-)。this

显式绑定

默认绑定和隐式绑定在我看来是js的一个内置且被动的绑定方式,就是已经这么帮你设定好了,只要符合这两个规则且没有其余规则存在那么this的指向就按照这两个规则来。显然,这类被动的绑定方式并不符合实际的代码编写须要,好比我要指定一个函数的this,该怎么办呢?这时候就须要显式绑定了。call、apply会在显式绑定时发挥做用。参考以下代码:编码

function foo() {
      console.log(this.a)
    }

    var obj1 = {
      a: 2
    }

    var a = 3

    foo.call(obj1) //2

输出结果为2。缘由是由于call改变了foo函数运行的this指向,将本来this指向的window全局转为了指向obj1,因此输出的是2,从这里也能够看出,显示绑定的优先级大于默认绑定。spa

new绑定

首先应该明确一点,JavaScript中的new与其余面向类的语言不一样,在js中new后面的只不过是一个普通的函数,仅仅是被new操做符调用了而已。使用new调用函数时,会执行以下步骤:

  1. 建立(或者说构造)一个全新的对象。
  2. 这个新对象会被执行[[Prototype]]链接。
  3. 这个新对象会绑定到函数调用的this。
  4. 若是函数没有返回其余对象,那么new表达式中的函数调用会自动返回这个新对象。

代码以下所示:

function foo(a) {
      this.a = a
    }

    var bar = new foo(2)

    console.log(bar.a) //2

输出结果为2。

不适用的状况

ES6中出现了一种特殊的函数:箭头函数。以上的四种规则在箭头函数中都不适用,箭头函数的是根据外层函数或者全局链决定this的。其实这也是对以往ES6以前的较为复杂的this绑定规则的优化和统一,在实际编码的过程当中更容易让人理解,固然箭头函数也有缺点,这里就再也不展开。

总结

在写这篇总结文章以前,一直对js中的this问题理解不深,翻了几遍《你不知道的js》才算真正有所学习和领悟。本文写的并不具体,就this绑定时的绑定丢失问题并无展开叙述,绑定的规则优先级也没有写全,暂时先留个坑,等忙完这阵再来补充-。- !

相关文章
相关标签/搜索