一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
JavaScript为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部this的指向问题,常用的有bind()、call()、apply()三种方法
这三个方法呢,他们的作用是改变函数执行时的上下文,emmm,就是改变函数运行时的this指向
关于this指向,俺之前有写过,诶嘿嘿
call、apply、bind都是Function对象的原型方法,它们是把特定的函数当作一个方法绑定到指定的对象上进行调用。最终的返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。
call()方法
call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的this指向
语法:函数名.call(thisArg,arg1,arg2...)
thisArg就是指定的对象,后面对应函数中的参数
案例:
var o = {
name: 'andy'
}
function fn(a, b) {
console.log(this);
console.log(a + b);
};
fn.call(o, 1, 2);
上面代码输出了this的指向以及 3 这个值。
apply()方法
同样的apply()方法调用一个函数。简单理解为是一种调用函数的方式 ,它也是可以改变this指向。
语法:函数名.apply(thisArg,[argsArray]);
thisArg就是指定的对象,但是第二个参数,必须是数组
案例:
var o = {
name: 'andy'
};
function fn() {
console.log(this);
console.log(arguments);
};
fn.apply(o,['ace','luffy']); // ①
fn(['ace','luffy']); // ②
以上代码,最后输出了this的指向,也就是o,然后看下面图片
①的结果:
②的结果:
通过内置对象argument输出获取的参数,两种调用方式对比后可以发现:
apply的精髓其实在于把传入的数组打碎变成参数列表,然后再把这个参数列表传递给你调用的函数
来看看apply方法主要应用,比如我们可以利用apply传一个数组,利用内置对象Math中的max()或者min()方法去求数组的最大或最小值。因为我们数组本身没有最大最小值的方法呀
var arr = [1, 66, 4, 88, 99];
// var max = Math.max.apply(null, arr);
var max = Math.max.apply(Math, arr);
console.log(max); //99
我们调用的是数学对象中的方法,不需要改变指向,所以传null,其实最好把null改为Math,指回去。
(诶嘿嘿,其实利用扩展运算符也可以,直接Math.max(...arr) ^_^ )
bind()方法
bind()方法呢不会调用函数,但是能够改变函数内部this指向
语法:函数名.bind(thisArg,arg1,arg2,...) thisArg就是你指定的对象,arg1这些是参数
→ bind返回的是由指定的对象和初始化参数改造的原函数拷贝! ←
案例1:
var o = {
name: 'andy'
}
function fn(a, b) {
console.log(this);
console.log(a + b);
};
fn.bind(o);
只这样写是不会调用函数fn的,这样只是让fn临时成为指定对象下的方法
刚刚我们说过,bind返回的是一个函数,我们可以试着接收一下
var f = fn.bind(o, 1, 2);
f(); //this指向了o,并输出了3
案例2:
来看看bind()方法的应用场景,如果有的函数不需要立即调用,但又想改变函数内部this指向
比如,我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
var btn = document.querySelector('button');
btn.onclick = function () {
this.disabled = true;
// var that = this; ②
setTimeout(function () {
this.disabled = false; // ①
// that.disabled = false ③
}.bind(this), 3000);
}
以上这么写。
问题①:setTimeout是window下的方法,this指向的是window,不会让这个按钮恢复
解决方案②、③:正常的写法就是在setTimeout方法外面用一个变量保存this的值,然后在定时器中调用这个变量即可。
👇来看看利用bind方法怎么写👇
var btn = document.querySelector('button');
btn.onclick = function () {
this.disabled = true;
setTimeout(function () {
this.disabled = false;
}.bind(this), 3000); // }.bind(btn), 3000);
}
btn不方便,可以用this,因为这个bind还是在btn这个对象里面,所以bind(this)指向的是btn
因为这个定时器临时成为btn对象中的一个方法,这样相当于是btn调用的,内部的this指向的是btn
就能 成功实现我们要的效果!