this的指向问题

原答案地址:https://zhuanlan.zhihu.com/p/23804247

 

最开始,先看一下,为什么这里的this输出结果并不一样?

var obj = {
    foo: function (){
        console.log("this-->>", this)
    }
}

var bar = obj.foo
obj.foo() //打印出来的this是obj
bar() //打印出来的this是window

 

一、函数调用

1、首先要从函数的调用讲起,JS里面有三种函数调用形式:

func(p1,p2)
obj.child.method(p1, p2)
func.call(context, p1, p2)

 

一般,我们知道前两种,并且认为前两种是优先于地上那种的。但实际上,第三种调用方式,才是正常的调用形式。

func.call(context, p1, p2)

 

其他两种方式是语法糖,可以等价地变换为call的形式。

func(p1, p2) //等价于
func.call(undefined, p1,p2)

obj.child.method(p1, p2) //等价于
obj.child.method.call(obj.child, p1, p2)

 

 

因此,我们的函数调用只有一种形式:

func.call(context, p1, p2)

 

这样,this就好解释了:

this,就是上面的context。

this是你call一个函数时传的context, 由于你从来不用call形式的函数调用,所以你一直不知道。

先看func(p1, p2)里的this是如何确定的:

function func(){
    console.log(this)
}
func() 
//等价于
function func(){
    console.log(this)
}
func.call(undefined)

 

按道理来说,打印出来的this应该是undefined,但是浏览器有一条规则:

如果你传的context是null或者undefined,那么window对象就是默认的context(严格模式下默认context是undefined),因此,上面打印的结果是window。

如果你希望this不是window,很简单:

func.call(obj) //这里的this就会是obj对象了

 

 

2、再来看obj.child.method(p1, p2)里的this是如何确定指向的:

var obj = {
    foo: function(){
        console.log(this)
    }
}
obj.foo()
//等价于 obj.foo.call(obj)

 

因此,this就是obj。

回到最开始的问题,obj.foo(),可以转化为obj.foo.call(obj), 因此,this就是obj。

bar()可以转化为 bar.call(), 由于没有传context,所以this就是undefined,根据浏览器默认原则,this指向的window。

 

二、 []语法

function fn(){console.log(this)}
function fn2(){console.log("this-->>", this)}
var arr = [fn, fn2]
arr[0]()

 

想一下,arr[0]()这里的this指的是什么?

我们可以将arr[0]()想成arr.0(),虽然后者的语法错了,但是形式与转换代码里面的obj.child.method(p1, p2)对应上了,于是:

arr[0]()可以转化为:arr.0(),接着转化为arr.0.call(arr), 那么,this值得就是arr了。

 

三、箭头函数

如果你在箭头函数里看到this,直接把他当做箭头函数外面this即可。外面的this是什么,箭头函数里面的this就还是什么,因为箭头函数本身不支持this。

 

四、总结

1、this就是当你call一个函数的时候,传入的第一个参数。this就是call的第一个参数。

2、如果你的函数调用形式不是call形式,可以按照“转化代码”转换为call形式。

 

posted @ 2021-01-16 16:43  qingshanyici  阅读(82)  评论(0编辑  收藏  举报