call,apply,bind有什么用?
call,apply和bind函数都是用于改变函数中this的指向。
call和apply区别
call和apply函数只有参数上的区别。如下面代码所示
function foo(x, y) {
console.log(x, y)
console.log(this)
}
const obj = {
name: 'obj'
}
// call函数在调用时传递给foo的参数要一个一个传递进去。
foo.call(obj, 1, 2) // 1, 2, obj对象
// apply函数在调用时传递给foo的参数要以数组的形式传递进去。
foo.apply(obj, [1, 2]) // 1, 2, obj对象
call,apply和bind的区别
call和apply函数都会执行原函数,而bind函数不会,它会返回一个绑定了this的函数。
function foo(x, y) {
console.log(x, y)
console.log(this)
}
const obj = {
name: 'obj'
}
// bind函数会返回一个新的函数,这个函数的this会被绑定为obj
// 同时传递给原foo函数的参数,可以在bind的时候传递进去,也可以在执行的时候再传递。
// 同样也可以bind的时候传递一部分参数,执行的时候传递剩下的部分参数。
const newFoo = foo.bind(obj, 1)
newFoo(2) // 1, 2, obj对象
call函数的实现
实现call函数的主要思路就是利用this的隐式绑定规则,当函数作为一个对象的属性时,通过对象 . 方法名的形式调用函数,函数中的this会被绑定为该调用对象。
Function.prototype.myCall = function (thisArgs, ...args) {
// 获取调用该方法的函数,在上面的例子中,这里的fn就是foo函数
const fn = this
// 边界判断,当用户绑定的值为null或者undefined是,将该this赋值为全局的this
// 当用户希望绑定的this为基本类型的数据,需要使用Object函数将其包装为包装对象
thisArgs = (thisArgs === undefined || thisArgs === null) ? globalThis : Object(thisArgs)
// 创建一个symbol作为key,防止属性名冲突。
const sym = Symbol()
// 将函数作为属性赋值给thisArgs
thisArgs[sym] = fn
// 执行fn函数,并将fn函数的执行结果返回出去
// 这里函数参数中将thisArgs中的sym属性给删除掉,是为了在函数内打印this对象时,不会有我们添加的sym属性。
return thisArgs[sym](...(delete thisArgs[sym] === true ? args : []))
}
apply函数的实现
在实现完call函数之后,apply函数就比较简单了,它和call函数只有参数上的不同。
// apply方法和call方法只有第二个参数的不同,在apply方法中这里的args必须为一个数组,所以我们不需要采用剩余参数的写法。
Function.prototype.myApply = function (thisArgs, args) {
// 如果想要对args参数的类型进行判断,可以自行判断,这里就不对该参数的类型进行判断了。
// 获取调用该方法的函数,在上面的例子中,这里的fn就是foo函数
const fn = this
// 边界判断,当用户绑定的值为null或者undefined是,将该this赋值为全局的this
// 当用户希望绑定的this为基本类型的数据,需要使用Object函数将其包装为包装对象
thisArgs = (thisArgs === undefined || thisArgs === null) ? globalThis : Object(thisArgs)
// 创建一个symbol作为key,防止属性名冲突。
const sym = Symbol()
// 将函数作为属性赋值给thisArgs
thisArgs[sym] = fn
// 执行fn函数,并将fn函数的执行结果返回出去
// 这里函数参数中将thisArgs中的sym属性给删除掉,是为了在函数内打印this对象时,不会有我们添加的sym属性。
return thisArgs[sym](...(delete thisArgs[sym] === true ? args : []))
}
bind函数的实现
bind函数和call,apply函数最主要的区别就是bing函数会返回一个绑定了this的函数,而不是调用它。
Function.prototype.myBind = function (thisArgs, ...args) {
// 获取调用该方法的函数,在上面的例子中,这里的fn就是foo函数
const fn = this
// 边界判断,当用户绑定的值为null或者undefined是,将该this赋值为全局的this
// 当用户希望绑定的this为基本类型的数据,需要使用Object函数将其包装为包装对象
thisArgs = (thisArgs === undefined || thisArgs === null) ? globalThis : Object(thisArgs)
// 创建一个symbol作为key,防止属性名冲突。
const sym = Symbol()
// 返回一个函数
return function(...args1) {
// 将第一次传递的参数和第二次传递的参数合并起来
const totalArgs = [...args, ...args1]
thisArgs[sym] = fn
return thisArgs[sym](...(delete thisArgs[sym] ? totalArgs : []))
}
}
总结
总体上来说,call和apply和bind函数的实现并不是很难,主要是利用了this的隐式绑定。