JS函数调用中this的指向问题详解
函数调用中的this
在讨论函数调用中的this
指向问题之前,我们首先需要知道为什么会有这样的问题,换个说法,也就是说在函数调用的过程当中,this
是从哪儿冒出来的。
实际情况是这样的:当函数被调用时,除了声明时规定需要接收的形式参数外,函数还会接收两个参数,分别是this
和arguments
,因此函数调用方式的不同就会导致this
的指向不同。
在js中函数的调用模式有4种:方法调用模式
,函数调用模式
,构造器调用模式
,apply调用模式
。
下面依次进行讲解。
方法调用模式
当一个函数作为一个对象的属性时,这个函数就被称为方法。
这个方法如果被调用(.方法名()
的形式),且方法中使用了this
,那么this
就被绑定到该对象。看下面的例子:
let myObject = {
value: 0,
increment: function(inc){
// 当这个 increment 方法被调用时,this 指向的是 myObject 对象
this.value += typeof inc === 'number'? inc : 1;
}
}
myObject.increment()
console.log(myObject.value); // 1
myObject.increment(2)
console.log(myObject.value); // 3
函数调用模式
当一个函数不是一个对象的属性时,那么它就是被当作函数调用的。被当作函数调用的时候,函数中如果使用this, this就会指向全局
感觉上面的话比较抽象?接着上面myObject
的例子,
给 myObject
添加一个 double
方法:
来分析一下,在 double
方法中,有一个 helper
函数,很明显,helper
函数不是 myObject
的属性,所以它不能被叫做方法。那在这个 helper
函数中用 this
, 看看会是什么结果
myObject.double = function(){
let helper = function(){
// 猜猜看,下面的 this 还会指向 myObject 吗? 答案是不会
// 这里的 this 会指向全局,全局中没有定义过 value, 所以这里的 this.value 的值是 undefined
console.log('helper中的this.value:'+this.value); // undefined
this.value = add(this.value,this.value)
console.log('此时的this.value:'+this.value); // undefined + undefined = NaN
}
helper()
}
myObject.double()
console.log(myObject.value) // myObjcet.value跟 double的调用毫无干系,值还是 3
那怎么样才能让内部函数 helper
也能访问到 myObject
中的 this
呢?
由于方法 double
方法是能访问到 myObject
的 this
的, 因此在double
函数中设置一个变量来接收this
的值就可以了, 然后内部函数helper通过这个变量就可以访问到 this
myObject.double = function(){
let that = this // 解决方法
let helper = function(){
that.value = add(that.value,that.value)
}
helper()
}
构造器调用模式
一个函数,如果创建的目的就是希望与 new
结合使用,那么这个函数就被称作构造器函数。
当这个构造器函数前面加上 new
来调用的时候,实际上背地里会创建一个连接到该构造器函数prototype
成员的新对象,同时 this
会绑定到该新对象上。
看个例子就明白了
let Quo = function(string){
this.status = string
}
Quo.prototype.getStatus = function(){
return this.status
}
let myQuo = new Quo('success')
console.log(myQuo.getStatus()) // 打印 success
apply
调用模式
首先需要明确的是:JavaScript是一门函数式编程语言, 所以函数可以调用方法。
当一个函数 (假设是函数A) 调用 apply
方法时, apply
方法会接收两个参数:
- 第一个参数是要绑定给
this
的值(也就是规定函数A的this
指向谁) - 第二个参数是要传递给函数A 的参数数组
下面举两个例子来说明apply
这两个参数的用法:
let arr = [3,4]
let sum = add.apply(null,arr) // sum 的值为 7
上面这个例子中, add函数
调用 apply
方法, arr
为 add函数
接收的参数数组, null
表示没有给 add 函数
指定 this
。而事实上 add 函数
中也没有用到this
, 所以也无需指定。
下面再来看一个指定了 this
的例子, 接着上面 Quo
构造函数的例子中的代码:
首先定义一个对象statusObj
let statusObj = {
status: 'failed'
}
let status = Quo.prototype.getStatus.apply(statusObj) // status的值为 failed
思考一下,为什么?
翻看上面的代码,可以看到 getStatus
函数中, 有 return this.status
, 而 apply
接收的参数是 statusObj
,也就是将 getStatus
函数中的 this
指向了 statusObj
, 所以结果就是 failed
。
好了,看到这里你应该对函数调用的四种模式,以及四种模式下的this指向问题有了更深的了解了吧! 如果发现了错误之处,还望及时指正哦!