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指向问题有了更深的了解了吧!
如果发现了错误之处,还望及时指正哦!