在平时写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的指向分为三种状况:
- 全局中的this
- 函数中的this
- 构造函数中的this
全局中的this
在浏览器中,全局中的this指向的是 window
,node.js中全局的this指向 globel
。
var a = 1;console.log(this); // windowconsole.log(this.a); // 1console.log(window.a); // 1console.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创建对象的过程:
- 创立一个新对象;
- 将构造函数的 this 指向这个新对象;
- 执行构造函数外部代码;
- 返回这个新对象
构造函数中的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