call、apply、bind的作用是改变函数运行时this的指向。
call
fun.call(thisArg[, arg1[, arg2[, ...]]])
call 方法第一个参数是要绑定给**this**的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。
使用:
var obj ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = obj.fn; b.call(obj,1,2) // 3
原理实现:分三步
-
第一步:给传入对象(执行上下文)新增一个函数(函数的行为和要调用的函数行为一样)
-
第二步:调用对象的新增的函数
-
第三步:删除对象的这个新增函数;
Function.prototype.call = function(obj) { obj.fn = this; obj.fn(); delete obj.fn; }
例:
function person(age) {
console.log(age)
console.log(this.name)
}
var obj = {
name: "test",
sex: "a"
}
Function.prototype.mycall = function (context) {
console.log(this);
}
person.mycall(obj, 18) // 上面的this会输出 person函数对象
Function.prototype.mycall = function (context) {
//context指向外部传入的执行上下文
var context = context || windows;
context.fn = this;//this指原函数, 这里相当于给传入的执行上下文对象新增了一个函数。
//将传入的参数存储起来
var args = [];
var len = arguments.length;
for (var i = 1; i < len; i++) {
args.push(arguments[i]);
}
//上面代码也可以换成
//args = Array.prototype.slice.call(arguments, 1);
var result = eval('context.fn(' + args.join(",") + ')'); //调用函数
delete context.fn; //删除执行上下文中新增的函数,不能改变原有对象
return result;
}
apply
apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。
fun.apply(thisArg, [argsArray])
var obj ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = obj.fn; b.apply(obj,[1,2]) // 3
自定义实现:
Function.prototype.myapply = function (thisArg, argsArray) { //thisArg指向外部传入的执行上下文 var thisArg = thisArg || windows, result;
thisArg.fn = this;//this指原函数, 这里相当于给传入的执行上下文对象新增了一个函数。
if(!argsArray){
result = thisArg.fn();
} else {
var newArgs = [];
for(let i = 0; i < argsArray.length; i++){ newArgs.push('argsArray['+i+']');
}
//上面代码也可以换成
//newArgs = Array.prototype.slice.call(argsArray, 1);
}
result = eval('thisArg.fn(' + newArgs + ')'); //调用函数 delete thisArg.fn; //删除执行上下文中新增的函数,不能改变原有对象 return result;
}
bind
和call很相似,第一个参数是**this的指向,从第二个参数开始是接收的参数列表**。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。
fun.bind(thisArg[, arg1[, arg2[, ...]]])
例:
var obj ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = obj.fn; b.bind(obj,1,2)() // 3
js实现:
if (!Function.prototype.bind) { //低版本可能不存在bind函数
Function.prototype.bind = function () {
var self = this, // 保存原函数
context = [].shift.call(arguments), // 保存需要绑定的this上下文
args = [].slice.call(arguments); // 剩余的参数转为数组
return function () { // 返回一个新函数
self.apply(context, [].concat.call(args, [].slice.call(arguments)));
}
}
}
区别
- 返回值:call和apply返回的是函数调用的结果; bind返回的是函数的引用。
- 参数列表:第一个参数都是上下文
this, call和bind第二个参数开始后接受的是参数列表;apply第二个参数是参数数组;