一、区别
1.相同点
- 三个函数都会改变this指向(调用这三个函数的函数内部的this)
2.不同点
- bind会产生新的函数(把对象和函数绑定后,产生新的函数)
- call和apply不会产生新的函数,只是在调用时绑定一下
- call和apply的区别:第一个参数都是要绑定的this,apply第二个参数是数组(函数的所有参数),call把apply的第二个参数单列出来
二、实现
1.call
实现思想:
- 首先context为可选参数,如果不传默认为window
- 给context创建一个fn属性,将值设置为需要调用的函数
- 因为call可以传入多个参数作为调用函数的参数,因此需要将参数延展出来
- 调用函数并将对象上的函数删除
Function.prototype.myCall = function(context){
if(typeof this !== "function"){
throw new TypeError("Error")
}
context = context || window
context.fn = this
const args = [...arguments].slice(1)
const result = context.fn(...args)
delete context.fn
return result
}
2.apply
实现思想:
- apply和call的区别在于对参数的处理,apply的第二个参数是数组
Function.prototype.myApply = function(context){
if(typeof this !== "function"){
throw new TypeError("Error")
}
context = context || window
context.fn = this
let result
if(arguments[1]){
result = context.fn(...arguments[1])
}else{
result = context.fn()
}
delete context.fn
return result
}
3.bind
实现思想:
- bind返回一个函数,函数存在两种调用方式:直接调用,通过new的方式
- 对于直接调用,选择了apply的方式实现,但是对于参数需要注意一下情况:因为bind可以实现类似fn.bind(obj,1)(2)这样的代码,所以我们需要将两边的参数拼接起来,于是就有了这样的实现args.concat(…arguments)
- 通过new的方式,不会被任何方式改变this,所以需要忽略传入的this
Function.prototype.myBind = function(context){
if(typeof this !== 'function'){
throw new TypeErroe('Error')
}
const _this = this
const args = [...arguments].slice(1)
return functions F(){
if(this instanceof F){
return new _this(...args,...arguments)
}
return _this.apply(context,args.concat(...arguments))
}
}