相同点:call()、apply()和bind()都可以改变函数内部的this指向
不同点请看下面实例:
call():
call方法既可以调用函数,又可以改变函数内的this指向。
var obj = {
name: 'andy'
}
function fn(a, b) {
console.log(this);
console.log(a+b)
};
fn(1,2)// 此时的this指向的是window 运行结果为3
fn.call(obj,1,2)//此时的this指向的是对象obj,参数使用逗号隔开,运行结果为3
应用场景: 经常做继承。参考下面这篇讲原型链的末尾部分:https://blog.csdn.net/caipital/article/details/108396438
出一个面试题:
function f1(a,b){
console.log(this) //输出f2
console.log(a+b) //输出3
}
function f2 (a,b) {
console.log(this)
console.log(a-b)
}
f1.call(f2,1,2) //打印输出f2 和 3
apply()
call方法既可以调用函数,又可以改变函数内的this指向。与call()的区别是函数调用时参数是数组
。
function fn(a,b){
console.log(this)
console.log(a+b)
}
let obj = {
name:'zy'
}
fn.apply(obj,[1,2]) //此时的this指向的是对象obj,参数传入了一个数组,运行结果为3
应用场景:数组运用到Math的API中
let a = Math.max(9,21,33);
console.log(a) //33
let arr = [9,21,33];
let res1 = Math.max(...arr)
let res2 = Math.max.apply(null,arr);
let res3 = Math.max.apply(Math,arr); // 推荐
let res4 = Math.max.apply(Function,arr);
console.log(res1) //33
console.log(res2) //33
console.log(res3) //33
console.log(res4) //33
bind()
bind()改变函数this指向,但不调用函数
,会生成一个新的函数
function fn(a,b){
console.log(this)
console.log(a+b)
}
let obj = {
name:'zy'
}
let new_fn1 = fn.bind(obj)
new_fn1(2,3) //this指向obj 打印输出5
let new_fn2 = fn.bind(obj,1,2)
new_fn2() //this指向obj 打印输出3
应用场景:当你想改变函数的this指向同时又不想立即执行函数的时候。
举个例子,一道经典面试题,在此题中体会bind()的用法吧。
要求:给三个按钮绑定点击事件,点击之后按钮变成不可点的状态,1秒之后恢复,变成可点击的状态。
方案一 :let 块级作用域
for(let i =0;i<btns.length;i++) {
btns[i].onclick = function() {
//表达式函数this指向绑定事件的对象
this.disabled = true;
setTimeout(function(){
btns[i].disabled = false;
},1000)
}
}
方案二:使用自调用函数(闭包思想)
闭包(closure):指有权访问另一个函数作用域中变量的函数。
for (var i = 0; i < btns.length; i++) {
(function (i) {
btns[i].onclick = function () {
//表达式函数this指向绑定事件的对象
this.disabled = true;
setTimeout(function () {
console.log(this) //Window
btns[i].disabled = false;
}, 1000)
}
})(i)
}
方案三: var that = this,储存this(闭包)
for(var i =0;i<btns.length;i++) {
btns[i].onclick = function() {
//表达式函数this指向绑定事件的对象
this.disabled = true;
var that = this;
setTimeout(function(){
that.disabled = false;
},1000)
}
}
方案四:使用 bind()改变this指向
for(var i =0;i<btns.length;i++) {
btns[i].onclick = function() {
//表达式函数this指向绑定事件的对象
this.disabled = true;
setTimeout(function(){
this.disabled = false;
}.bind(this),1000)
}
}