如果你是个js的初学者,当决定使用js来开创一个新世界的时候,你会突然遇到很多摸不到头脑的问题,比如继承,块作用域,或者现在的主题,this关键词。js中的this到底是什么?我们为什么每次使用它的时候,都会忘记它的使用场景和环境。有时候当我们尝试用之前的经验来处理的时候发现,what?为什么跟我的设想不一致?那么好,现在你就可以花费你打一把游戏的时间,来跟随我看一下,this到底是什么。
js的内存包括两个部分,执行栈和内存堆。js运行时会维护一系列的栈,当前的栈总是处在内存栈的栈顶,所以this变量就会随着栈的操作(pop/push)而改变指向的对象。
-
普通函数
默认的执行栈是全局的,如果一段代码在普通函数中调用,this会指向默认的全局对象,window或者global,视运行环境而定。当然,如果我们在代码中启用了严格模式use stirct;
,那么在严格模式下,this指向的是undefined
。可以参考以下的示例:function normalFunc() { console.log(this); console.log(this === window); // or global } function useStrictNormalFunc() { 'use strict'; console.log(this); console.log(this === window); // or global }
-
构造函数
js中的构造函数,其实和普通函数没啥区别,除了它可以使用new来实例化(但是普通函数也可以使用new的啊)。哦还有一个区别,构造函数首字母是大写(当然没有任何规定,但是如果你小写,那肯定会带来惊喜的)。function Person(name) { this.name = name; } const person = new Person("fengxh"); // person.name = "fengxh";
当我们使用new来实例化的时候,此时构造函数内的this指向的是实例对象,实例过程中为实例创造了多个属性来达到我们创建构造函数的目的,这样person其实就是被构建出来的实例。除非我们手动为Person返回一个对象类型数据,否则Person默认返回的就是this(如果手动return基础数据,则也会被默认返回this)。
-
对象的方法调用
function normalFunc() { console.log(this); } const person = { normalFunc }; normalFunc(); // window or global or undefined person.normalFunc(); // yes, it's person. no!! why person
对象的方法调用,this会指向对象本身,而不是全局变量。那么我们接着再看。
const myFunc = person.normalFunc; myFunc(); // window or global
哈哈,这里因为myFunc是普通的函数调用,所以this还是指向到全局变量,而不是person了。那么,我们再接着看。
const person = { normalFunc: function() { console.log(this); // person function innerFunc() { console.log(this); // window or global } innerFunc(); } };
这里innerFunc还是作为一个普通函数被调用,所以this指向为全局变量。当然这里的函数定义都是普通定义,如果遇到箭头函数,那么情况又会不一样,这种情况我们随后再说。
-
call,apply和bind
const a = { name: "a" }; const b = { name: "b" }; function log() { console.log(this.name); } log.call(a); // "a" log.call(b); // "b" log(); // undefined
如果我们在执行时改变this的绑定,那么会产生意外的惊喜,函数中的this会被绑定到我们指向的那个对象,而不是全局变量window。Interesting。call和apply都可以动态改变函数中的this指向,他们的不同点是call的参数第一个是改变this的绑定指向,第二个及以后都是作为普通函数的参数被调用,而apply的第一个参数和call一样,第二个函数则是参数数组,等同于arguments。而bind则是修改函数的this指向的对象,然后返回一个函数,不同于前两者都是直接会调用
- 箭头函数
详细定义的地方请看阮大师的介绍箭头函数定义
箭头函数是不持有this的,所以它的this是属于外层的(此处不完全精确,希望读者可以自行阅读相关文献)。而且它不能作为构造函数使用,不能被call/apply/bind处理来达到改变函数里this指向的目的,它不持有this。
好了,看完这篇文章大家有没有学习到,有没有总结出下次遇到this再怎么处理它的问题。如果大家有什么疑问,或者对文章的理解有不同之处,请指出互相学习。谢谢。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。