很多学java的同学在接触js之后使用this的时候都是懵逼的,这特么怎么回事,怎么老是给我报“Cannot read property 'xxx' of undefined”,我的this.xxx.xxx明明已经有值啊,为什么会出现这种情况。
面对上面的问题,很多js的初学者都会很懵,不知道js的this为什么就不指向自己想要的那个this了。
我以前也遇见过这种疑惑,直到我后来学习了一个大佬的博客(至于是谁的我还真忘了),我彻底弄懂了js的this为什么这么调皮了。
在js中,函数的调用有三种方式:
1. 直接调用:例如a(...params)
2. 对象调用:例如obj.a(...params)
3. new 函数调用:例如new A(...params)
但其实这些都是语法糖。
直接调用其实写完整就是:
a.call(undefined,...params)
对象调用写完整是:
obj.a.call(obj,...params)
而使用 new 调用函数的时候,例如
var a = new A(...params)
其实写完整是:
var a = {} a.call(a, ...params) a.__proto__ = A.prototype
这就是this为什么会乱跳的根本原因所在。
在js中,根据函数的调用方式不同,this的指向变化也不同:
1. 直接调用函数,this指向全局:
这里会因为环境不同而产生不同的结果:
在严格模式下,this是undefined,但是我们大部分代码都是在非严格模式下写的,所以不探讨这个情况。
在非严格模式下,浏览器环境下this会指向window,node环境中会指向global。
以浏览器代码为例:
function a(){ console.log(this) } a()
显示结果是:
这里出现的问题是最多的,因为很多时候函数都是直接调用的,所以this会直接指向window,导致取值错误。
2.对象调用函数,this指向调用对象:
先看代码:
const obj = { a:1, b: function (){ console.log(this.a) } }
obj.b()
这个打印出来结果是1,毋庸置疑。因为这个this指向调用对象obj,所以this.a就是obj.a。
再看一个代码:
const obj = { a:1, b:{ a:2, b:function (){ console.log(this.a) } } } obj.b.b()
这里打印的是多少呢。把代码在浏览器中运行一下:
是2,因为obj.b.b()就相当于obj.b.b.call(obj.b),所以this指向obj.b,那么打印出来的自然是obj.b.a。
再看一段代码:
var a = 'This is brower'
const obj = { a:1, b:function(){ console.log(this.a) } } const fn = obj.b fn()
这里打印的是多少呢。把代码在浏览器中运行一下:
这是为什么?
这是因为fn = obj.b = function(){...},在这里的fn被赋值 function(){...},跟obj.b没有关系了,所以直接调用fn其中的this指向window,而window.a则是 'This is brower'。
3. 使用构造函数调用,this 指向创建的对象:
照例,先看代码:
function A(){ this.a = 1 this.b = 2 } var a = new A() console.log(a.a) console.log(a.b)
这里打印出来的自然是1和2,因为new A()过程中将this指向了a。
但是在这里有个坑,就是构造函数的返回值如果是引用类型的值就会引发错误,会直接将this指向返回的对象。
function A(){ this.a = 1 return { a:2 } } var a = new A() console.log(a.a)
在浏览器中运行查看结果:
上图中可以看出,a指向的是A返回的对象,所以a.a打印出的是2。
返回的如果是一个数组的话,a也会指向返回的数组,a.a就会打印出 undefined。
在es6中出现了箭头函数,箭头函数中的this始终指向函数所处的块级作用域的this。
看代码:
var a = 'This is window'
const obj = { a: 1, b: () => { console.log(this.a) } } obj.b()
上答案:
是不是又懵了,明明是obj调用的,但是this却指向了window。
这就是箭头函数的优点,因为它的this指向是固定的,永远指向所处的块级作用域内部的this。
在这里obj.b所处的块级作用域就是全局,所以其中的this指向window。
再来一段代码:
function a(){ this.a = 10 return { a:1, b:()=>{ console.log(this.a) } } } const obj = a() obj.b()
继续直接上答案:
这次差不多懂了吧,这个箭头函数创建的时候是处于方法 a 的作用域内部的,所以箭头函数内部的this始终指向方法 a 中的this。
上述就是我在学习js中的this时遇到的所有关于this的调用的问题,估计应该可能大概差不多maybe是有没有涉及到的,但是关于this的这些差不多够了。