一、call() / apply()
JavaScript中的函数是对象,与其他JavaScript对象一样,JavaScript函数也有方法。其中有两个自带的方法 – call和apply,可以利用这两个方法来间接调用某个函数。
通过一个简单的例子体会一下call和apply的用法:
function f(){
console.log(this.name)
}
let obj = {name:"obj"}
f.call(obj) // => obj :调用函数f,并指定this值为obj对象
f.apply(obj) // => obj :调用函数f,并指定this值为obj对象
上面的代码类似于下面的程序:
let obj = {name:"obj"}
obj.f = f;// 在对象上定义一个属性指向f函数对象
obj.f();
delete obj.f;
从第一段程序看,call和apply没什么区别。事实上两个方法的区别确实很小,只在传递参数形式上有去区别。
两个方法,只有参数形式的区别
apply的参数要求是数组或类数组对象
下面是一段给apply、call方法传递多个参数的程序,看看它们之间的区别:
function f(p1, p2) {
console.log(this.name, p1, p2)
}
// f.apply(obj,1,2) // => 报错:Uncaught TypeError: ...called on non-object
f.apply(obj, [1, 2]);//obj 1 2 : 传递给函数的参数需要采用数组或类数组的形式
let arrlike = { 0: "1", 1: "2", length: 2 };
f.apply(obj, arrlike);// => obj 1 2 : 传递给函数的参数需要采用数组或类数组的形式
let obj = { name: "obj" }
f.call(obj, 1, 2) // => obj 1 2 :调用函数f,并指定this值为obj对象,传递两个实参给f函数
⚠️ apply传递参数需要采用数组或类数组的形式,否则报错
apply使用场景
ES6前替代扩展操作符 – 将参数数组转换为参数列表
let max = Math.max(2,3,5,7,0);
console.log(max);// 7
max = Math.max([2,3,5,7,0]);
console.log(max);// NaN
max = Math.max(...[2,3,5,7,0]);
console.log(max);// 7
max = Math.max.apply(Math,[2,3,5,7,0]);
console.log(max);// 7
箭头函数问题
⚠️ 箭头函数调用call/apply
方法,第一个参数会被忽略(因为箭头函数的this值在定义时绑定)。
var name = "window"
let arrow_fun = (v) => {
console.log(this.name,v);// window 1
}
let normal_fun = function(v){
console.log(this.name,v);// window 1
}
var obj = {
name: "obj"
}
arrow_fun.call(obj, 1, 3); // window 1:箭头函数中第一个参数(obj)被忽略,实参3无参数接收被忽略
normal_fun.call(obj, 1, 3);// obj 1:实参3没有参数接收被忽略
二、bind方法
( bind()方法的主要目的是把函数绑定到对象 . 这句话会让人误以为给对象添加了一个新方法)
其实,bind方法是利用现有函数,创建并返回一个新的函数,同时为其绑定了一个对象为this。
(apply和call是绑定this并直接调用)
function f(y) {
return (this.x + y);
}
let o1 = { x: 1 };
let fbo1 = f.bind(o1);//bind方法是利用现有f函数,创建并返回一个新的函数,同时绑定了o1为新函数的this
// o1.f(); // 报错: Uncaught TypeError: o.f is not a function
console.log(fbo1(2)); // => 3
let o2 = { x: 90, fbo1 };
console.log(o2.fbo1(10)); // => 11: fbo函数仍然与o绑定.
⚠️ o1.f()
报错 ,bind并没有给对象添加了一个新方法!
柯里化
bind方法不但可以绑定对象为新函数的this,还能为函数绑定参数
function f(y) {
return (this.x + y);
}
let o1 = { x: 1 };
let fbo1 = f.bind(o1,9);//bind方法是利用现有f函数,创建并返回一个新的函数
//同时绑定了o1为新函数的this;
//还绑定的新函数的第一个参数的值一直为9
console.log(fbo1(2)); // => 10 函数的参数已经绑定了9,再传参就无效了
返回的新函数上绑定o1为this值,同时绑定了一个参数值9,见下图
从图中可以看出,绑定的参数是以数组的形式绑定的。
三、总结
// call/apply绑定对象为this,并直接执行
函数.call(绑定的对象,参数1...参数n);
函数.apply(绑定的对象,[参数1...参数n]);
// 仅绑定对象为this并返回新函数,并不执行
函数.bind(绑定的对象);