下面为了理解,我们将调用函数function称为FunA,第一个参数为context.
1、首先要明确的是: call、apply、bind是Function方法,调用call、apply、bind必须是函数.
2、call、apply、bind目的:context可以使用FunA里面的方法.
3、call、apply、bind语法
- call语法: FunA.call(context, arg1, arg2, arg...)
- apply语法:FunA.apply(context, [argsArray])
- bind语法:FunA.bind(context,arg1,arg2,...)
4、call、apply、bind有什么功能?
call:
- 改变FunA内部的this指向,使this指向context
- 将arg1, arg2, arg...这种形式的参数置于实参之前传递给FunA.
apply:
- 改变FunA内部的this指向,使this指向context
- 将[argsArray]这种形式的参数置于实参之前传递给FunA.(与call的区别,参数形式不同)
bind:
- 改变FunA内部的this指向,使this指向context
- 将arg1,arg2,...这种形式的参数置于实参之前传递给FunA.
- 返回一个函数
4、根据具体功能写call、apply、bind实现思路
- call和apply实现思路:
- 判断是否是函数调用,若非函数调用抛异常
- 通过新对象(context)来调用函数
- 给context创建一个属性
fn
,将
fn
设置为需要调用的函数.(此时被调用的函数内部this指向context,这就实现了改变this指向问题) - 结束调用完之后删除
fn
- 给context创建一个属性
- bind实现思路
- 判断是否是函数调用,若非函数调用抛异常
- 返回函数
- 判断函数的调用方式,是否是被new出来的
- new出来的话返回空对象,但是实例的__proto__指向_this的prototype\
- 完成函数柯里化
Array.prototype.slice.call()
- 判断函数的调用方式,是否是被new出来的
5、手写call、apply、bind
call:
Function.prototype.myCall = function (context) {
// 1、判断是否是函数调用,若非函数调用抛异常
if (typeof this !== 'function') {
throw new TypeError("Not a Function")
}
// 不传参数默认为window
context = context || window
// 2、通过新对象(context)来调用函数
// 给context创建一个属性fn,将fn设置为需要调用的函数.
context.fn = this
// 保存参数
let args = Array.from(arguments).slice(1) //Array.from 把伪数组对象转为数组
let result = context.fn(...args)
//结束调用完之后删除fn
delete context.fn
// 返回结果
return result
}
apply:
Function.prototype.myApply = function (context) {
if (typeof this !== "function") {
throw new TypeError("Not a Function");
}
context = context || window;
// 保存this
context.fn = this;
// 是否传参
let result
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn()
}
delete context.fn
return result
}
bind:
Function.prototype.myBind = function(context){
// 判断是否是一个函数
if(typeof this !== "function") {
throw new TypeError("Not a Function")
}
// 保存调用bind的函数
const _this = this
// 保存参数
const args = Array.prototype.slice.call(arguments,1)
// 返回一个函数
return function F () {
// 判断是不是new出来的
if(this instanceof F) {
// 如果是new出来的
// 返回一个空对象,且使创建出来的实例的__proto__指向_this的prototype,且完成函数柯里化
return new _this(...args,...arguments)
}else{
// 如果不是new出来的改变this指向,且完成函数柯里化
return _this.apply(context,args.concat(...arguments))
}
}
}
这里bind还不够详尽,后面再重开一个,只写bind