网上关于this的指向问题的博客文章很多,但大多数都是复制粘贴,也不能用简洁的语言讲清楚,而是不停地写一些示例,看得人云里雾里。
其实关于this的指向并不难,只是没有人去做一个好的总结和试验,导致这个问题莫名其妙被复杂化了。
这一集,我只给出结论,以及判定的通用方法,至于是否确实如我所讲,大家可以自行验证。
画图理解
假设我们现在有一个函数foo,要判断其中this的指向,可以根据下图来分析:
第一步,判断函数是什么类型:箭头函数、普通函数还是绑定类函数(bind、call、apply);
对于箭头函数,需注意,首先箭头函数其实是没有 this 的,箭头函数中的 this 只取决包裹箭头函数的第一个普通函数的 this。如果往上级找一直没找到包裹它的普通函数,那么该箭头函数中的this指向全局对象。在浏览器中,全局对象当然就是window;
而对于绑定函数来说,this指向我们自定义的参数,在bind/call/apply中,即是第一个参数,第一个参数在浏览器环境中的缺省值为window。这种情况属于人为地改变this指向,顺带一提:如果对一个函数进行多次bind,只有第一次的bind是生效的,这属于一个语法知识。
第二步,对于普通函数来说,又分两种情况:是被当作构造函数调用,还是被当作普通函数调用。
如果是通过new关键字对其进行实例化,也就是把这个函数当作构造函数使用,那么this恒指向实例化后的对象,此时的this是一个地址指针,指向实例化过程中在堆内存新开辟的用于存储实例化对象的那一块空间;
如果是当作普通函数调用,那么谁调用它,this就指向谁。有一种情况是类似于foo()这样的调用,在浏览器中其实这相当于window.foo()。所以调用者为全局对象window,this便指向window。
当然,有时候会出现混合调用的情况,这时候就需要根据优先级来决定,优先级排名如下:
构造函数(new)> 绑定函数(call/apply/bind)> 具体对象调用(obj.foo())> 全局对象调用(foo())