「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
bind、call、apply 异同点
相同点:
- 调用者都是且必须是函数
- 改变函数执行时的上下文,即改变this指向
区别:
call: fun.call(thisArg, param1, param2, ...)
使用一个指定的
this
值和单独给出的一个或多个参数来调用一个函数,返回调用结果
apply: fun.apply(thisArg, [param1,param2,...])
使用一个指定的
this
值和单独给出的 一个或多个参数的数组 来调用一个函数,返回调用结果
bind:fun.bind(thisArg, param1, param2, ...)
改变调用功函数的
this
指向,返回一个新的函数,不需要调用
如何实现
call:
原本功能:
function fn(a, b) {
console.log('a ', a);
console.log('b ', b);
console.log('this ', this);
return 'test'
}
console.log(fn('d', 'e'))
// a d
// b e
// this Window {…}
// test
const res = fn.call({ c: 'c' }, 'd', 'e')
console.log('res ', res)
// a d
// b e
// this { c: 'c' }
// res test
const res1 = fn.call(null, 'd', 'e')
console.log('res1 ', res1)
// a d
// b e
// this Window {…}
// res1 test
实现思路 myCall(ctx, ...arg)
- 设置
this
指向 - 给
ctx
设置临时函数,将函数的this隐式绑定指向到ctx上(此处为了防止绑定的对象中本身就存在与临时函数相同的字段,可以使用Symbol
规避) - 执行临时函数并传递单数
- 删除临时函数
- 返回结果
Function.prototype.myCall = function (ctx, ...args) {
if (ctx === null || ctx === undefined) {
ctx = globalThis
}
let fun = Symbol(1)
ctx[fun] = this
const result = ctx[fun](...args)
delete ctx[fun]
return result
}
const res2 = fn.myCall({ c: 'c' }, 1, 2)
console.log('res2 ', res2)
// a 1
// b 2
// this { c: 'c', fun: [Function: fn] }
// res2 test
const res3 = fn.myCall(null, 1, 2)
console.log('res3 ', res3)
// a 1
// b 2
// this Window {…}
// res3 test
apply
原本功能:
function fn(...args) {
console.log('arr ', ...args);
console.log('this ', this);
return 'test apply'
}
console.log(fn(['d', 'e']))
// arr (2) ['d', 'e']
// this Window { … }
// test apply
const res = fn.apply({ a: 11 }, [3, 4, 'e'])
console.log('res ', res)
// arr 3 4 e
// this { a: 11 }
// res test apply
实现思路 myApply(ctx, ...arg)
- 实现思路跟
call
完全一样 arguments
是一个类数组,es6中函数可以使用解构获取arguments
,因此其实现代码除了参数,其他都一样
Function.prototype.myApply = function (ctx, args = []) {
if (args && !(args instanceof Array)) {
throw(`${args} 不是一个数组!`)
}
if (ctx === null || ctx === undefined) {
ctx = globalThis
}
let fun = Symbol(1)
ctx[fun] = this
const result = ctx[fun](...args)
delete ctx[fun]
return result
}
const res2 = fn.myApply({ a: 121 }, [4,'r'])
console.log('res2 ', res2)
// arr 4 r
// this {a: 121, fun: ƒ}
// res2 test apply
const res3 = fn.myApply(null, [4,'r'])
console.log('res3 ', res3)
// arr 4 r
// this Window { … }
// res3 test apply
bind
原本功能:
for (var i = 1; i <= 5; i++) {
// 缓存参数
setTimeout(function (i) {
console.log('bind', i) // 依次输出:1 2 3 4 5
}.bind(null, i), i * 1000);
}
实现思路 myBind(ctx, ...args)
- 区别于
call
、apply
,bind
只需要返回绑定后的函数,不需要执行 bind
接收的参数都需要传递到绑定后的函数
Function.prototype.myBind = function (ctx, ...args1) {
if (ctx === null || ctx === undefined) {
ctx = globalThis
}
return (...args2) => {
let fun = Symbol(1)
ctx[fun] = this
ctx[fun](...args1.concat(args2))
delete ctx[fun]
}
}
好了,这就是本次的手写分享~~