手写 apply、call、bind 函数
2024年7月24日大约 2 分钟
手写 apply、call、bind 函数
call()
以给定的 this 值和逐个提供的参数调用该函数
Function.prototype._call = function (context, ...args) {
// context 为传入的 this,不传时默认为全局对象
if (!context) context = globalThis
// 传入指向为值类型时,转化为对象
if (typeof context !== 'object') context = new Object(context)
// 使用 Symbol 防止覆盖同名属性,此时 this 为调用 _call 的函数本身
const fnKey = Symbol()
context[fnKey] = this
// 执行函数,得到结果
const result = context[fnKey](...args)
// 删除新增的属性,防止污染
delete context[fnKey]
// 返回结果
return result
}
function fn(a, b, c) {
console.log(this, a, b, c)
}
// 结果中输入 this 会有 Symbol 函数,最终会被删除
fn._call({ x: 100 }, 10, 20, 30) // { x: 100 } 10 20 30
fn._call({ x: 200 }, 40, 50) // { x: 200 } 40 50 undefined
fn._call({ x: 300 }, 60) // { x: 300 } 60 undefined undefined
apply()
以给定的 this 值和作为数组(或类数组对象)提供的 arguments 调用该函数
Function.prototype._apply = function (context, args) {
// context 为传入的 this,不传时默认为全局对象
if (!context) context = globalThis
// 传入指向为值类型时,转化为对象
if (typeof context !== 'object') context = new Object(context)
// 使用 Symbol 防止覆盖同名属性,此时 this 为调用 _apply 的函数本身
const fnKey = Symbol()
context[fnKey] = this
// 执行函数,得到结果
const result = context[fnKey](...args)
// 删除新增的属性,防止污染
delete context[fnKey]
// 返回结果
return result
}
function fn(a, b, c) {
console.log(this, a, b, c)
}
// 结果中输入 this 会有 Symbol 函数,最终会被删除
fn._apply({ x: 100 }, [10, 20, 30]) // { x: 100 } 10 20 30
fn._apply({ x: 200 }, [40, 50]) // { x: 200 } 40 50 undefined
fn._apply({ x: 300 }, [60]) // { x: 300 } 60 undefined undefined
bind()
创建一个新函数,当调用该新函数时,它会调用原始函数并将其 this 关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面
Function.prototype._bind = function (context, ...bindArgs) {
// context 为传入的 this,不传时默认为全局对象
if (!context) context = globalThis
// 传入指向为值类型时,转化为对象
if (typeof context !== 'object') context = new Object(context)
// bindArgs 为传入的 参数,不传时默认为空数组
bindArgs = bindArgs ? bindArgs : []
// 当前 this 为调用 _bind 的函数本身
const self = this
// 返回函数
return function (...args) {
// 拼接参数
const newArgs = args ? bindArgs.concat(args) : bindArgs
self.apply(context, newArgs)
}
}
function fn(a, b, c) {
console.log(this, a, b, c)
}
const fn1 = fn._bind({ x: 100 }, 10, 20, 30)
const fn2 = fn._bind({ x: 200 }, 40, 50)
const fn3 = fn._bind({ x: 300 }, 70)
fn1() // { x: 100 } 10 20 30
fn2(60) // { x: 200 } 40 50 60
fn3(80, 90) // { x: 300 } 70 80 90