面试官:手写 call、apply 及 bind 函数

call 函数

简介

call 函数的用法

js 复制代码
    fn.call(obj,1,2);
  • call() 函数中的第一个参数表示:想让 this 指向的对象 (obj);
  • call() 函数中的第二及以后参数表示:传进去的实参;

call 函数的功能:

  • 让函数立执行;
  • 可改变 this 的指向;
  • 可实现继承问题;

call 函数的调用

js 复制代码
const user1 = {
    name : '张三',
    age : 10
}
const user2 = {
    name: '李四',
    age: 20
}

function say(){
    console.log('name:', this.name)
    const sum = [...arguments].reduce((res, current)=> {
        res = res + current
        return res
    })
    console.log(sum);
}

say.call(user1, 1,2,3)
say.call(user2, 4,2,3)

以上是一个 call 函数调用的示例

  • 定义了两个对象分别是 user1 与 user2
  • 定义say()函数,输出当前调用的 name 与剩余参数的求和结果
  • 通过 call 函数执行 say 函数,分别传参 user1 与 user2

分别将当前 this 绑定至 user1 与 user2 ,输出结果为:

手写 call 函数

下面我们自己来实现 call 函数:

js 复制代码
const user1 = {
    name : '张三',
    age : 10
}
const user2 = {
    name: '李四',
    age: 20
}

function say(){
    console.log('name:', this.name)
    const sum = [...arguments].reduce((res, current)=> {
        res = res + current
        return res
    })
    console.log(sum);
}

Function.prototype.myCall = function(ctx, ...args){
    ctx = (ctx===null || undefined)? globalThis : Object(ctx)
    const key = Symbol('temp');
    Object.defineProperty(ctx, key, {
        enumerable: false,
        value: this
    })
    const result = ctx[key](...args)
    delete ctx[key]
    return result

}
say.myCall(user1,1,2,3)
  • 首先还是先定义对象 obj 与 obj2,函数 say()
  • 在函数原型上新增 myCall方法,接收两个参数,ctx 为必填参数表示 this 的指向,...args接收剩余参数
  • 判断 ctx 的是否为 null 或者 undefined,如果是的话,当前 this 指向 globalThis, (globalThis旨在通过定义一个标准的全局属性来整合日益分散的访问全局对象的方法。该提案目前处于第四阶段,这意味着它已经准备好被纳入ES2020标准。所有流行的浏览器,包括Chrome 71+、Firefox 65+和Safari 12.1+,都已经支持这项功能。你也可以在Node.js 12+中使用它。)
  • 需要给ctx 定义个属性将剩余参数传入进去,为了避免与绑定的 ctx 参数重复,使用 Symbol()定义 key 值

  • 定义的 key 值通过 Object.defineProperty(obj,key,decriptor)方法传入,obj为目标对象,key 为 属性 值,descriptor是我们操作属性的具体描述,这里我们使用enumerable不可被枚举,具体包含的参数有:

    • value:被定义的属性的值,默认值为undefind
    • writable:是否可以被重写,也就是value属性是否可以被赋值,当writable的值为true的时候,可以被重写,反之不可以。
    • enumerable:该属性是否可以被枚举,值为true可以被枚举,反之则不可以。
    • configurable:该属性是否可以被删除,或者是否可以被修改,值为true可以被删除或者被修改,反之则不可以。
  • 将剩余参数传递给定义好的函数

  • 将定义的属性删除,return 结果出去

  • 最后,使用 say().myCall(user1,1,2,3)调用,输出的结果为:

总结

使用 globalThis 可以在浏览器以及 node 环境上运行,Symbol定义唯一 key 值等操作

apply函数

简介

apply 函数跟 call 函数的区别在于穿参形式不一样,apply 函数的第二个参数是一个数组,示例:

js 复制代码
const user1 = {
    name : '张三',
    age : 10
}
const user2 = {
    name: '李四',
    age: 20
}

function say(){
    console.log('name:', this.name)
    console.log('args:',[...arguments])
    const sum = [...arguments].reduce((res, current)=> {
        res = res + current
        return res
    })
    console.log('sum:',sum);
}


say.apply(user1, [1,2,3])
say.apply(user2, [2,3,4])

运行结果:

手写 apply 函数

将 myCall 函数改造 下

js 复制代码
const user1 = {
    name : '张三',
    age : 10
}
const user2 = {
    name: '李四',
    age: 20
}

function say(){
    console.log('name:', this.name)
    console.log('args:',[...arguments])
    const sum = [...arguments].reduce((res, current)=> {
        res = res + current
        return res
    })
    console.log('sum:',sum);
}

Function.prototype.myApply = function(ctx, ...args){
    ctx = (ctx===null || undefined)? globalThis : ctx
    const key = Symbol('temp');
    Object.defineProperty(ctx, key, {
        enumerable: false,
        value: this
    })
    console.log(...args)
    // 注意该处的传参形式
    const result = ctx[key](...args[0])
    delete ctx[key]
    return result

}
say.myApply(user2,[2,3,4])

bind 函数

相关推荐
崔庆才丨静觅1 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax