答对这道this指向问题,就是真的入门了!

117 阅读4分钟

前端小白,写文章主要用于记录学习收获,写的不对欢迎指出~还请大佬轻喷👀

今天看到一个this指向的题目,感觉考的非常全面,快来看看你们能不能全部答出来吧~

    var name = 'window'
    var person1 = {
      name: 'person1',
      show1: function(){
        console.log(this.name)
      },
      show2: () => {
        console.log(this.name)
      },
      show3:function() {
        return function(){
          console.log(this.name)
        }
      },
      show4:function() {
        return () => {
          console.log(this.name)
        }
      }
    }
    var person2 = { name: 'person2' }
    
    person1.show1()
    person1.show1.call(person2)
    person1.show2()
    person1.show2.call(person2)
    person1.show3()()
    person1.show3().call(person2)
    person1.show3.call(person2)()
    person1.show4()()
    person1.show4().call(person2)
    person1.show4.call(person2)()
    
    // 答案在下面,不要偷看~
person1
person2
window
window
window
person2
window
person1
person1
person2

全部答对并且分析得十分清晰的小伙伴,恭喜你,几乎已经掌握this了,可以退出文章了!😁

没答对的,要好好听课了哦😎

我们都知道this有四种绑定方式(如果有不知道this的四种绑定方式的小伙伴,赶紧移步别的文章或观看《你不知道的JavaScript-上卷》相关部分),其实这意味了一点:函数内部的this是什么我们是不能确定的,只有在函数真正运行的时候我们才能知道函数内部的this是什么!也就是说,我们不能在不调用函数的情况下确定其内部的this指向~(箭头函数除外,箭头函数内部的this就是其声明时所在作用域的this

好了,总的来说就是必须记住一点:普通函数只有在运行时才能确定其内部this指向!

接下来开始解题啦!

1、person1.show1(): show1是一个普通函数,所以其内部this与其运行时有关。又因为通过隐式绑定,即绑定向了person1,所以自然就输出person1,很简单。

2、person1.show1.call(person2):对于这题,我们要明确一点:四种this绑定规则是有优先级的,他们的优先级是:new绑定 > 显示绑定 > 隐式绑定 > 默认绑定。这题同时应用了隐式绑定与显示绑定,但因为显示绑定优先级高,所以自然就输出person2了。

3、person1.show2(): show2是一个箭头函数,且在对象初始化的时候它就已经声明了,既然声明了,那么它的this就永远指向它声明时所在位置的this!那么此时它声明所在位置的this是什么呢?有人可能会觉得是person1自身,大错特错!对象自身是没有this的!! 那么箭头函数此时就继续向上级寻找this,发现了window,那么他就永远指向window了~所以自然输出window

4、person1.show2.call(person2): 这里试图通过显示绑定更改this指向。但是我们说过,箭头函数内部的this一经声明就不可修改。所以仍然输出window

5、person1.show3()(): 这里首先会调用person1.show(),返回了一个普通函数,这个返回的函数其实就是这样的

function fn(){console.log(this.name)}  // 随便起一个名字

然后直接调用这个函数:

fn()

我们会发现,其实就是在全局上调用了一个普通函数,也就是默认绑定,那么其内部的this也就是window了

6、person1.show3().call(person2)

首先,和第五题一样返回了一个函数fn。然后执行fn.call(person2),也就是应用显示绑定,那么函数内部this就指向person2了,所以自然输出person2

7、person1.show3.call(person2)()

首先执行第一个函数,也就是person1.show3.call(person2),此时show3内部的this确实指向person2,但这并没啥用,show3内部的函数并没有执行,所以不会有任何输出。然后同样返回了一个fn,然后在全局执行了fn

fn()

发现仍然是在全局上执行fn,应用默认绑定,所以仍然输出window。

8、person1.show4()()

show4返回的是一个箭头函数,箭头函数内部this的指向与其声明时所在环境的this有关。注意:其所在环境的this是可能变化的哦!

要注意:虽然show4声明了,但是其返回的箭头函数还没有声明哦!只有在执行show4时,其内部的箭头函数才被声明!

在这里,同样首先执行show4。可以看到,show4是作为对象的方法调用的,也就是隐式绑定,所以此时show4内部的this指向为person1。 然后执行以下代码

return () => {console.log(this.name)}

那么这里的this是啥嘞?有小伙伴可能一下子没看出来,其实上面的代码可以等价为以下代码

var fn = () => {console.log(this.name)}
return fn

这样是不是就亲切多了?此时箭头函数在show4内部被声明,而show4内部this指向为person1,所以箭头函数fn内部的this就永远指向person1了,自然输出person1。

9、person1.show4().call(person2)

这里,和第八题一样返回了一个箭头函数,并且箭头函数内部的this永远指向person1了,通过显示绑定也是不可以修改滴~所以仍然输出person1

10、person1.show4.call(person2)()

首先执行person1.show4.call(person2),show4此时应用了显示绑定,所以show4内部的this此时是指向person2的。然后再进行箭头函数的声明:

var fn = () => {console.log(this.name)}
return fn

箭头函数在被声明时,发现自身所在作用域的this时person2,那么箭头函数内部的this就永远指向person2了!所以自然输出person2。

好啦!!洋洋洒洒又写了一千多字。有问题欢迎指正~😜