目录
对比
相同
- 均能改变this的指向
- 接收的第一个参数均为this指向的对象
- 后面的参数都可以进行传参
不同
- 参数:call和bind相同,均支持多个参数依次传入;apply仅支持数组或类数组
- 调用:call和apply在运行时都调用了函数,而bind不调用
简单实现
call
分析
function.call(thisArg, arg1, arg2, ...)
1.调用function:function必须存在且是一个函数,之后调用并返回
if (typeOf this !== "function") {
throw new TypeError("error")
}
result = this() //当前为function
return result
2.传入参数thisArg,如果没有传入参数,则默认为window
context = context || window
3.指针从function变化为thisArg(这里相当于给thisArg添加一个fn属性,值为function)
context.fn = this
- 最后需要删除
delete context.fn
4.取参数call传的参数(从第二个开始截取)
let args = [...arguments].slice(1)
5.调用函数并传参
result = context.fn(...args)
6.返回值
整体代码
Function.prototype.myCall = function (context) {
if (typeOf this !== "function") {
throw new TypeError("error")
}
context = context || window
context.fn = this
let args = [...arguments].slice(1)
let result = null
result = context.fn(...args)
delete context.fn
return result
}
apply
分析
apply(thisArg)
apply(thisArg, argsArray)
整体上和call一样,只有参数不同,apply第二个参数为数组
- 获取数组以及调用
- 传参:如果传入了数组,则使用展开运算符
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
整体代码
Function.prototype.myApply = function (context) {
if (typeOf this !== "function") {
throw new TypeError("error")
}
context = context || window
context.fn = this
let result = null
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
bind
Function.prototype.myBind = function (context) {
//1.判断调用对象是否为函数
if (typeOf this !== "function") {
throw new TypeError("error")
}
//2.保留当前函数的引用,获取其余值传入参数
var fn = this
var args = [...arguments].slice(1)
//3.创建函数返回
return function Fn() {
//4.调用apply
return fn.apply(
//判断函数作为构造函数的情况
this instanceof Fn ? this : context,
args.concat(...arguments)
)
}
}