关于javascript:彻底理解js中this的指向问题

4次阅读

共计 2471 个字符,预计需要花费 7 分钟才能阅读完成。

在平时写 js、react 等等这些代码的时候,常常会遇到应用 this 的状况,当本人信念满满的写完代码,点击运行的时候,发现报错 this.xxx is undefined 或者 this.xxx is not a function,但本人的代码外面明明定义了 xxx 的。
为什么会呈现这些谬误呢,其实就是 this 指向的对象外面没有定义的 xxx
所以搞懂 this 的指向是十分有必要的。

一、执行上下文

在开始说 this 之前,先简略说一下执行上下文
执行上下文有三个局部:

  • 变量对象(Variable Object,VO)
  • 作用域链
  • this

这里外面的 this 就是本文要说的 this

执行上下文又分为:

  • 全局执行上下文
  • 函数执行上下文

全局执行上下文是在代码执行时就创立了,函数执行上下文是在函数调用的时候创立的,同一个函数,在不同时刻调用,会创立不同的执行上下文

二、this 的指向

因为 this 存在于执行上下文当中,而执行上下文又是在代码执行和函数调用的时候创立的,所以 this 的指向也是在代码执行和函数调用时确定的。

能够 this 应用的不同场景,将 this 的指向分为三种状况:

  1. 全局中的 this
  2. 函数中的 this
  3. 构造函数中的 this

全局中的 this

在浏览器中,全局中的 this 指向的是 window,node.js 中全局的 this 指向 globel

var a = 1;
console.log(this);  // window
console.log(this.a);  // 1
console.log(window.a);  // 1
console.log(this === window);  // true

函数中的 this

依据函数调用形式,又能够分为以下两种状况:

  • 当函数作为对象中的办法被调用时的 this
  • 当函数被独立调用时的 this

1、对象办法中的 this
当函数作为对象中的办法被调用时,函数中 this 指向的是,函数的拥有者。

var a = 111;
var obj = {
    a: 222,
    func: function() {console.log(this);  // obj
        console.log(this.a);  // 222
    }
}
obj.func();

在这里 func 函数,作为 obj 对象 外面的办法被调用,所以 func 外面的 this 指向的就是 func 函数 的拥有者,在这里就是 obj

2、被独立调用时
当函数被独立调用时,函数外面的 this 就指向全局上下文外面的 this,即 window;在 严格模式 下,this 使 undefined

var a = 111;
function func1(){
    var a = 222;
    console.log(this);  // window
    console.log(this.a);  // 111
}
func1();

function func2(){
    "use strict"
    console.log(this);  // undefined
}
func2();

ES6 箭头函数中的 this

箭头函数中 this 指向是在 函数定义 时确定的,这一点和申明式函数定义有所区别。
在箭头函数定义时,函数 this 指向,定义时所在 执行上下文外面的 this

var func = () => {console.log(this);  // window
}
func();

func 函数是一个箭头函数,所以 func 函数外面的 this 是在其定义是确定的,定义时所在的执行上下文是全局执行上下文,上下文中的 this 指向的是 window,所以 func 函数的 this 指向的也是 this。

var a = 111;
var obj = {
    a: 222,
    func: function() {var fun2 = () => {
            var a = 333;
            console.log(this.a);
        }
        fun2();}
}
obj.func();

在这段代码里,当 func 函数 调用时,func 外面的 this 指向的是 obj,在 func 函数外面定义了一个箭头函数,所以 func2 函数 外面的 this 指向的是 func 函数 执行上下文外面的 this,所以最初打印进去的是 obj 对象 外面的 a(222)

** 构造函数中的 this

构造函数 new 创建对象的过程:

  1. 创立一个新对象;
  2. 将构造函数的 this 指向这个新对象;
  3. 执行构造函数外部代码;
  4. 返回这个新对象

构造函数中的 this 指向生成的对象

function Obj(a){
    this.a = a;
    this.func = function(){console.log(this);
        console.log(this.a);
    }
}
var obj = new Obj(2);
obj.func();

在这段代码当中,在应用 new 实例化对象之后,调用对象外面的 func 函数,这里的 func 函数就是 obj 对象 外面的一个办法,所以 func 函数外面的 this,就指向函数的拥有者,所以这里打印的后果是 2

三、扭转 this 指向的办法

能够应用 call,apply,bind 来扭转函数外面的 this 的指向

var a = 111;
var obj1 = {
    a: 222,
    func: function() {console.log(this); // {a: 333}
        console.log(this.a); // 333
    }
}
        
var obj2 = {a: 333,}
obj1.func.call(obj2,);

这里调用 obj1 外面的 func 办法的时候,在前面加了一个 call,它会吧 func 外面的 this 扭转为指向 call 外面指定的 obj2,所以最初打印的是 333,在这里调用 call,函数会立刻执行。

apply 办法和 call 的作用是一样的,他们之间的区别就是,call 在传递其余参数时,是一个一个传的,而 apply 是传递一个数组,这样当传递的数据个数增多的时候,就不必像 call 一样,挨个写道 call 前面的括号里了。
比方:

obj.func.call(obj2,param1,pram2,param3)
obj.func.aplly(obj2,[param1,pram2,param3])

bind 也能够扭转函数外面的 this 指向,它和 call 和 apply 的区别就是,它返回一个新的函数,并不会和 call 和 apply 一样立刻执行。

参考资料
MDN-this

正文完
 0