前端小白,写文章主要用于记录学习收获,写的不对欢迎指出~还请大佬轻喷👀
今天看到一个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。
好啦!!洋洋洒洒又写了一千多字。有问题欢迎指正~😜