一、apply、call、bind的基本用法
1-1、apply
语法: func.apply(thisArg, [argsArray])
参数:
- thisArg
- 必选,func函数运行时this的指向
- argsArray
- 可选,数组/类数组对象。作为参数传递给func函数
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
1-2、call
语法: func.call(thisArg, arg1, arg2, ...)
参数:
- thisArg
- 必选,func函数运行时this的指向
- arg1, arg2,...
- 可选,指定的参数列表
function sum(num1, num2) {
console.log(this);// {}
return num1 + num2;
}
var result = sum.call({}, 10, 20);
console.log(result); // 30
1-3、bind
语法: func.bind(thisArg[, arg1[, arg2[, ...]]])
参数:
- thisArg
- 必选,func函数运行时this的指向
- arg1, arg2,...
- 可选,指定的参数列表
返回值: 返回一个原函数的拷贝,并且拥有指定的this值和初始参数
var obj = {
name: 'zs'
}
function foo() {
console.log(this);
}
var bar = foo.bind(obj);
bar(); // {name: 'zs'}
二、apply、call、bind的异同
相同点:
- 都用于显示绑定this
- 第一个参数如果传递为null或undefined,则this默认指向window
不同点:
- 传递参数形式和返回值不同
- 第一个参数都接收this指向,但apply第二个参数接收的是一个数组或类数组对象
- call与bind第二个参数接收的是参数列表
- apply与call调取后立即执行,并将this绑定为指定的内容;而bind不是立即执行,而是返回一个原函数的拷贝
三、apply、call、bind的简单实现
3-1、实现apply
Function.prototype.myApply = function(thisArg, argsArray) {
// 1 获取要执行的函数
// fn.apply(xx, xxx)由隐式绑定规则可以得到,this即所要执行的函数
var fn = this;
// 2 处理一下thisArg,如果传递null或undefined则this指向window;否则包装为对象
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window;
// 3 将执行函数给传递的this(进行隐式绑定)
thisArg.fn = fn;
var result;
argsArray = argsArray || [];
// 4 执行
result = thisArg.fn(...argsArray);
// 5 执行完去删除一下,防止有多余的属性
delete thisArg.fn;
// 6 返回结果
return result;
}
- 执行apply时,是通过 函数.apply(xxx)的方式来执行的,相当于进行了隐式绑定,所以可通过this获取到执行函数
- 要为传递的this进行判断是否为null和undefined,如果是则this指向window,否则指向传递的对象
- 注意,要进行Object包裹,一旦传入基本数据类型,要指向其包装类型。如传递数字则this指向Number,传递字符串则this指向String
- 将执行函数再给thisArg,通过thisArg去发起调用,这样通过隐式绑定的原理,this便指向了发起调用的对象thisArg (this绑定规则详见上一篇文章~)
3-2、实现call
Function.prototype.myCall = function(thisArg, ...args) {
var fn = this;
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window;
thisArg.fn = fn;
var result = thisArg.fn(...args);
delete thisArg.fn;
return result;
}
3-3、实现bind
Function.prototype.myBind = function(thisArg, ...args) {
var fn = this;
thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg): window;
function newFn(...args2) {
thisArg.fn = fn;
// 合并参数
var finalArgs = [...args, ...args2];
var result = thisArg.fn(...finalArgs);
delete thisArg.fn;
return result;
}
return newFn;
}
// 调用
function sum(num1, num2, num3, num4) {
console.log(num1, num2, num3, num4)
}
var newSum = sum.myBind("abc", 1,2);
var result = newSum(3,4); // 1,2,3,4
- 调取bind后返回的新函数也可接收多个参数,会与调取bind传递的参数进行合并