在JavaScript中,函数也是一种对象,JavaScript函数也有自己的方法。通过call()和apply()方法,我们可以间接地调用函数。这两个方法允许我们指定调用某个函数时的this值,这意味着可以将任意函数作为任意对象的方法来调用,即使这个函数实际上并不是这个对象的方法。call()方法将自己参数列表作为函数的参数,而apply()方法则使用数组值作为参数。
call()和apply()的第一个参数都是调用这个函数的对象,它将作为这个函数的调用上下文,在函数体内将作为this的值。
1 let obj = { 2 attr1: 1, 3 attr2: 2, 4 } 5 6 function func(arg1, arg2) { 7 let attr1 = 3; 8 //console.log(this); 9 console.log(this.attr1, arg1, arg2); 10 } 11 12 func(1, 2); //undefined 1 2 13 func.call(obj, 1, 2); //1 1 2 14 func.apply(obj, [1, 2]); //1 1 2
从输出结果可以看出,call()和apply()将第一个参数obj作为被调用函数的this值,而后续的所有参数都将传递给被调用的函数。如果函数在定义时可以接收任意多个参数,则可以将任意长度的数组作为apply()的第二个参数。
1 nums = [1,2,3,4,5,6,7,8,9]; 2 let biggest = Math.max.apply(Math, nums); 3 console.log(biggest); //9
另外需要注意的是,由于箭头函数从定义它的上下文中继承this值,因此这个this值不能通过call()和apply()方法重写。如果对箭头函数调用call()和apply()方法,那么它们的第一个参数实际上会被忽略。
1 let obj1 = { 2 attr1: 1, 3 attr2: 2, 4 } 5 6 let func = (arg1, arg2) => { 7 console.log(this.attr1, this.attr2, arg1, arg2); 8 } 9 10 11 func(1,2); //undefined undefined 1 2
12 func.call(obj1, 1, 2); //undefined undefined 1 2
13 func.apply(obj1, [1, 2]); //undefined undefined 1 2
bind()方法的主要目的是将函数绑定到对象。如果在函数func上调用bind()方法并传入对象o,则这个方法会返回一个新函数。调用这个新函数就如同将func作为o的方法一样调用,传递给这个新函数的所有参数都会传递给func函数。
1 function func(arg) { 2 console.log(this.x + arg); 3 } 4 5 let o = {x : 1}; 6 let func1 = func.bind(o); 7 func1(2); //3 8 let p = {x : 10, func1}; 9 p.func1(2); //3
从输出结果可以看出,bind()方法将func被绑定到了对象o上面并返回func1,调用func1本质上就是在o上调用func,即将func函数体中的this值修改为了o。即使将func1作为其他对象的属性,这个this值也不能被重写。
另外需要注意的是,箭头函数从定义它们的环境中继承this值,因此这个值不能被bind()重写。
1 let func = (arg) => { 2 console.log(this.x + arg); 3 } 4 5 let o = {x : 1}; 6 let func1 = func.bind(o); 7 func1(2); //NAN。this始终指向全局对象
事实上 ,除了将函数绑定到对象,bind()方法还会做其他事。bind()方法可以将其第一个参数之后的参数绑定到原始函数的形参上。
1 let sum = (x, y) =>{ 2 console.log(x + y); 3 } 4 5 let succ = sum.bind(null, 1); 6 succ(2); //3 7 8 function func(y, z) { 9 console.log(this.x + y + z); 10 } 11 12 let g = func.bind({x : 1}, 2); 13 g(3); //6