函数内this指向问题
这些 this 的指向,是当我们调用函数的时候确定的。 调用方式的不同决定了this 的指向不同,一般指向我们的调用者。
JavaScript 为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部 this 的指向问题,常用的有 bind()、call()、apply() 三种方法。
call()方法
- 可以调用函数
- 可以改变函数内部this指向
- 可以实现继承
用法:
fun.call(thisArg, arg1, arg2, ...)
-
thisArg:在 fun 函数运行时指定的 this 值
-
arg1,arg2:传递的其他参数
-
返回值就是函数的返回值,因为它相当于调用了函数
// 改变函数内this指向 js提供了三种方法 call() apply() bind()
// 1. call()
var obj = {
name: 'charlie'
}
function fn(a, b) {
console.log(this)
console.log(a + b)
}
fn.call(obj, 1, 2)
// call 的主要作用可以实现继承
function Father(uname, age, sex) {
this.uname = uname
this.age = age
this.sex = sex
}
function Son(uname, age, sex) {
Father.call(this, uname, age, sex) // 在Son方法里面调用了Father方法,并且把Father方法里面的this指向修改成指向Son方法,从而实现了继承
}
var son = new Son('刘德华', 18, '男')
console.log(son)
apply()方法
- 可以调用函数
- 可以改变函数内部this指向
- 参数必须是数组(伪数组)
- 主要作用 借助数学对象Math求数组中的最大最小值等
用法:
fun.apply(thisArg, [argsArray])
- thisArg:在fun函数运行时指定的 this 值
- argsArray:传递的值,必须包含在数组里面
- 返回值就是函数的返回值,因为它相当于调用了函数
// 改变函数内this指向 js提供了三种方法 call() apply() bind()
// 2. apply()
var obj = {
name: 'charlie'
}
function fn(arr) {
console.log(this)
console.log(arr) // 'pink'
}
fn.apply(obj, ['pink'])
// 1. 也是调用函数 第二个可以改变函数内部的this指向
// 2. 但是他的参数必须是数组(伪数组)
// 3. apply 的主要应用 比如说我们可以利用 apply 借助于数学内置对象求数组最大值
// Math.max()
var arr = [1, 66, 3, 99, 4]
// var max = Math.max.apply(null, arr)
var max = Math.max.apply(Math, arr)
var min = Math.min.apply(Math, arr)
console.log(max, min) // 99 1
bind()方法
- 不调用函数
- 可以改变函数内部this指向
- 返回由指定的this值和初始化参数改造后原函数拷贝,即返回原函数改变this指向之后产生的新函数,因此当调用bind()方法时如果想要马上调用,需要用一个变量接收过来,然后再调用(如第14,15行代码)
- 主要应用 如果有函数不需要立即调用,但又想改变this指向,例如定时器setTimeout
用法:
fun.bind(thisArg, arg1, arg2, ...)
- thisArg:在 fun 函数运行时指定的 this 值
- arg1,arg2:传递的其他参数
<button>点击禁用我,3秒后自动恢复</button>
<button>点击禁用我,3秒后自动恢复</button>
<button>点击禁用我,3秒后自动恢复</button>
// 改变函数内this指向 js提供了三种方法 call() apply() bind()
// 3. bind()
var obj = {
name: 'charlie'
}
function fn(a, b) {
console.log(this)
console.log(a + b)
};
var f = fn.bind(obj, 1, 2)
f()
// 1. 不会调用原来的函数 可以改变原来函数内部的this 指向
// 2. 返回的是原函数改变this之后产生的新函数
// 3. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时用bind
// 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
// var btn1 = document.querySelector('button');
// btn1.onclick = function() {
// this.disabled = true; // 这个this 指向的是 btn 这个按钮
// // var that = this;
// setTimeout(function() {
// // that.disabled = false; // 定时器函数里面的this 指向的是window
// this.disabled = false; // 此时定时器函数里面的this 指向的是btn
// }.bind(this), 3000); // 这个this 指向的是btn 这个对象
// }
var btns = document.querySelectorAll('button')
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
this.disabled = true
setTimeout(function() {
this.disabled = false
}.bind(this), 3000) // 这个this指向的是btn,于是就将34行里面this修改成btn
}
}
call()、apply()、bind()方法总结
-
相同点
- 都可以改变函数内部this指向
-
不同点
- call 和 apply 会调用函数, 并且改变函数内部this指向.
- call 和 apply 传递的参数不一样, call 传递参数 aru1, aru2…形式 apply 必须数组形式[arg]
- bind 不会调用函数, 可以改变函数内部this指向.
-
主要应用场景
- call 经常做继承
- apply 经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
- bind 不需要立即调用,但又想改变this指向