当前位置: 首页 > 科技观察

图解:彻底理解JS中this指向问题的文章

时间:2023-03-13 21:51:31 科技观察

Javascript是一种基于对象的动态语言,也就是说,一切都是对象。一个典型的例子就是函数也被看成是普通的Object。其中,这是实现面向对象的一个??非常重要的特性,但是这在Javascript中是非常容易产生误解的,尤其是长期接触静态语言的同学。而且,这在面试和实际项目中是最重要的,所以我必须单独拿出一篇文章来理解它。上文提到,this参数是Javascript面向对象编程的重要组成部分,代表与函数调用相关联的对象,也称为函数上下文。我知道,你可能是JS的初学者,如果你不明白,没关系,不用担心,因为下面有动画可以更好地理解。思维导图1.这是什么?这是什么?我们上面说这是一个对象,它是一个什么样的对象呢?让我们输入代码并打印出来。我们最常见的this在函数中。调用JS函数有两种方式。一种是直接调用,一种是通过new调用。我们用两种方式来打印this的值是否相同?。控制台输出如下:yelling?嗯?虽然都在函数里,但是为什么打印出来不一样呢?通过函数调用直接打印出来的this指向全局变量Window;通过new方法调用的函数被认为是Constructor,为了能够创建实例对象,它的this值指向生成的实例对象。那么我们通过上面的乱七八糟的操作就知道这是一个对象,但是我们不同的操作中this指向的对象是不一样的。写到这里,知道这是什么东西就够了。接下来,我们就来慢慢深究这个的原理。2、如何判断这个?既然知道this是什么,那么如何判断this的值呢?也是我们上面没有解决的问题。这指向三种情况。只要了解这三种情况,就不用死记硬背了。你可以如鱼得水地判断这一点,并且可以在面试的时候流利的告诉面试官。this指向的三种情况:(1)对象调用,this指向对象(之前谁调用this就指向谁)。对于第一种情况,this通过对象调用指向谁?要找出答案,您必须实践它。小鹿,上传代码,okay~。控制台打印:通过我们自己的测试,发现this指向的是obj,于是得出结论,谁调用了函数,this就指向谁,很简单,我们继续往下看。(2)对于直接调用的函数,this指向全局的window对象。其实这也属于第一种情况。如果我们直接在全局函数中调用函数,实际上调用函数的是全局对象Window。根据我们从第一篇文章得出的结论,谁调用函数,this就指向谁,想必大家已经知道,第二种情况,this指向Window。(3)通过new,this总是绑定到新创建的对象上,this的指向不能以任何方式改变。刚才我们也测试了第三种方法。这指向生成的对象实例。很多好奇的朋友都会问小鹿。他们对new的内部实现及其作用感到好奇。事实上,这并不复杂。我不想告诉你。你估计你也可以从上面两个结论中得出。我们从得到的结果推导,通过new,this指向生成的对象实例,那么我们猜测实例对象内部一定调用了函数,所以this指向生成的对象实例。这是真实情况吗?确实,我们的new进程实际上在内部创建了一个空对象,然后把构造函数传入的参数和属性挂在这个空对象上,然后返回这个对象。它还涉及到将空对象挂载到原型链上。想了解更多的可以自己去探索,这里就不多说了。延伸:箭头函数的this指向谁?我们都知道在ES6之后,为了更方便的使用函数,我们会在项目中使用箭头函数。写法:运行程序,控制台输出:我们可以断定this在箭头函数中,因为箭头函数没有单独的this值。箭头函数的this与声明它的上下文相同。也就是说,在调用箭头函数时,并不会隐式调用this参数,而是继承函数定义时的上下文。关于箭头功能,一定要注意,面试的时候经常会挖坑!3.如何改变this的值?我们已经按照这个方向颠倒过来了,但是不要狂妄自大,你需要找一些关于这个的大厂面试题自己做,巩固和加深自己的理解。这可以指向不同的对象。我们有什么办法可以改变这种情况吗?是的,有三种方法可以改变这一点。下面详细看看这三种方法的实现和区别,这也是面试的重点!(1)call方法call方法用于改变this的方向。具体先看例子,控制台输出如下:(2)apply方法再看apply方法。同样的例子:控制台输出如下:我们发现输出值是一样的,我们先不比较两者的区别,继续看bind函数。(3)bind方法我们以bind函数为例,控制台输出如下:(4)call、apply、bind有什么区别?三者我们都跑了例子,我们开始总结,我们先看看三者的共同点是什么?共同点:都可以改变this的指向,传递的第一个参数是this指向的对象。三者均采用后续传参的形式。三者的相同点表面上能看出来,功能也一样,但是对于不同点,就牵涉到细节了。不知道大家有没有发现呢?不同点:调用的参数是单独传递的,而apply后续传递的参数是数组的形式,但是bind没有规定既可以传递值也可以传递数组。call和apply函数的执行是直接执行的,而bind函数会返回一个函数,等我们要调用的时候再执行。你可能会有疑问,小鹿,你表面上是这样看的吗?虽然我们表面上看得出来,但何不手写一个call,apply,bind。看完源码的实现,你会觉得这三个函数没有什么难的。因为涉及到时间问题,就不说了。小鹿贴出下面的代码。如果你有兴趣,可以研究一下。手写调用函数:手写apply函数:手写bind函数:PS:如果我们用上面的方法改变箭头函数的this指针,会发生什么?可以通过对齐来改变吗?由于箭头函数没有自己的this指针,通过call()或apply()方法调用函数时,只能传递参数(不能绑定this),它们的第一个参数会被忽略。