-
call、apply、bind通常用来改变函数或者对象的this指向,不同之处是call和apply返回的是this改变之后的执行结果,而bind返回的是一个函数,call接收n个参数,第一个目标对象,后面的可以是调用call函数的参数,apply和call除了参数之外其它基本一样,apply接收两个参数,第二个是一个数组,bind和call的区别就是bind返回的是一个函数
-
apply实现
Object.prototype.myApply = function (fn) {
// fn为undefined或者null时,根据条件将其设为global或者window
if(!fn){
fn = typeof window === "undefined" ? global : window
}
let result
let args = [...arguments[1]]
fn.x = this if(!args){
result = fn.x()
}else{
result = fn.x(...args)
}
return result
} -
call实现原理
Object.prototype.myCall = function (fn) {
// fn为undefined或者null时,根据条件将其设为global或者window
if(!fn) {
fn = typeof window === "undefined" ? global : window
}
let result
let args = [...arguments].slice(1)
fn.x = this if(!args){
result = fn.x()
}else{
result = fn.x(...args)
}
return result
} -
bind实现原理
Object.prototype.myBind = function(fn) {
if(!fn){
fn = typeof window === "undefined" ? global : window
}
let arges = [...arguments].slice(1)
// 提前拿到this,防止this改变
let that = this
const F = function (){
let args = [...arguments]
if(this instansceof F) { //考虑new F的情况
return that.call(this,...arges,...args )
}
return that.call(fn,...arges,...args )
}
// 维护原型 if(this.prototype) {
F.prototype = this.prototype
}
return F
} -
测试用例
const a = {
name: "jake",
age: 15,
skill: ["swimming","basketball"]
}
name = "hello"
function b(a,b){
let name = "mike"
console.log(a,b)
return this.name
}
function B(name,age){
this.name = name
this.age = age
}
B.prototype.show = function(){
console.log(this.name, this.age)
}
let c = B.myBind(null, "mini")
let d = new c(19)
d.show()//mini 19
console.log(d)//B { name: 'mini', age: 19 } -
个人觉得,其实bind方法有点像柯里化,同样可以达到延迟函数执行以及保存公用变量的功能,在实现bind的时候因为返回的是一个函数,所以可以使用new操作符强行改变this,在实现的时候需要注意,还有就是要记得维护调用函数的原型