前言
大家都知道这三个方法可以改变this指向,但是如果经常不用很容易忘记又有点模糊,今天又复习了一遍做一个整理。当然我也会顺便说一说每一种方法的运用场景,毕竟了解一个知识点就应该知道这个知识点的作用。
call方法
详解
call的第一个参数是一个对象,函数中的this指向这个对象,后面的参数就是传递到函数中的各种各样的参数。fn函数定义在全局中,我们通过call(o,1,2)让函数调用时候的this变成了o,执行函数结果为3.控制台打印的结果如下图所示。
const o = {
name: 'linglong'
}
function fn(a,b) {
console.log(this);
console.log(a + b);
};
fn.call(o,1,2);
运用
call可以实现函数的继承,具体如何实现呢,我们来看代码。
function father(name, age) {
console.log(this);
this.name = name;
this.age = age;
}
function son (name, age) {
father.call(this, name, age);
}
var son1 = new son();
son1('linglong', 20);
console.log(son1);
apply
详解
aplly与call类似,第一个参数也是this,后面的参数就是传到函数的实参,但是必须是一个数组(伪数组)类型。
var o = {
name: 'linglong',
}
function fn(arr) {
console.log(this);
console.log(arr);
}
fn.apply(o, ['ningjing']);
运用
apply改变this的指向与call不一样的是传递的参数是一个数组,然后输出的时候是一个字符串,利用这个特点我们可以数组的最大值最小值。
const arr = [121, 112, 33, 5454];
var max = Math.max.apply(null,arr)//apply方法将arr传递给Math.max函数
var min = Math.min.apply(window, arr);
console.log(max, min);
但是第一个参数null不太好,最好指向函数的调用者,Math调用了max函数,让null改成Math。
bind方法
bind我之前写过一篇文章,这里就直接引用了。
特性
bind可以改变this的指向,但是他不会去执行这个函数,什么意思呢?我们来看代码
- 例1
var futher = function (name){
this.name = name;
},
function son (){
console.log(this);
}
son.bind(futher)
在这个例子里面并不会让son函数执行,这是bind的特性之一。但是son里面的this指向了futher,这是bind的特性之二。
- 例二
var o = {
name: 'andy'
};
function fn(a, b) {
console.log(this);
console.log(a + b);
};
var f = fn.bind(o, 1, 2);
f();
bind会有一个返回值,这个返回值是改变this后返回的新函数。这个例子里面bind首先将fn函数里面的this指向o对象。然后参数1,2传递给了fn函数里面的a和b。然后执行f函数,this打印结果是o对象,a+b结果是3。
小tip:
bind的第三个特性是返回一个新函数,这与第1个特性不执行函数不矛盾,上面的例子我们用f接收了这个新函数再执行才有了结果哦。
bind特性的总结
我们简单总结一下,bind有3个特点。
- 第一函数不执行。
- 第二是bind里面的第一个参数就代表了this。
- 第三个是会返回一个改变了this的新函数。
bind案例功能
我们有一组按钮,点击某个按钮后为了防止多次点击使按钮禁用。三秒后再开启按钮。
案例代码
// 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
// var btn1 = document.querySelector('button');
// btn1.onclick = function() {
// this.disabled = true; // 这个this 指向的是 btn 这个按钮
// setTimeout(function() {
// btn1.disabled = false; // 此时定时器函数里面的this 指向的是btn
// }, 3000)
// }
在这个例子里,我们通过选择器获取到了按钮,在点击事件发生后执行的函数里面,先通过disabled让button禁用。然后设计一个定时器,我们知道在定时器里面的this指向的是window,所以this.disabled = false会报错滴,于是乎改成了btn1.disabled。但是这样写不够优雅,假如我们的按钮变量名修改了那么计时器里面的操作也要随着更改。那么如何优化呢? 我们可以在定时器外面var that= this;定时器里面函数that.disabled= false.
如何让定时器函数里面的this指向按钮而不是btn呢,我们可以利用call,apply,bind改变this。
利用bind优化案例代码
我们知道改变this前面说了三种关键字,那么用哪种更好呢,毫无疑问bind比较合理。因为bind不仅改变了this而且不会立即调用函数。而是通过定时器去触发这个函数。代码如下
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对象
}
}
定时器函数里面的this指向的是window,而bind不在定时器函数里面,在btn.onclick函数里面,所以bind(this)中的this是btn对象。当某个btn对象被点击的时候,让disabled生效,三秒后执行定时器函数,bind的特性是函数不会立即执行,所以让定时器函数内部的this变成btn后三秒后再执行,dispaled失效解除禁用。
三种方法的总结
- 三种方法都可改变this指向
- call改变this指向,将参数单个传递给函数后立即调用函数。
- apply改变this指向,将参数数组传递给函数后立即调用函数。
- bind改变内部的this指向但不会立即调用函数
- call经常用于继承
- apply和数组有关比如求数组的最大值最小值
- bind不会调用函数但是可以改变this指向,比如改变定时器函数的this。