面试官:手写 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 函数

相关推荐
Uyker2 分钟前
从零开始制作小程序简单概述
前端·微信小程序·小程序
还有几根头发呀1 小时前
UDP 与 TCP 调用接口的差异:面试高频问题解析与实战总结
网络·网络协议·tcp/ip·面试·udp
Dontla3 小时前
为什么React列表项需要key?(React key)(稳定的唯一标识key有助于React虚拟DOM优化重绘大型列表)
javascript·react.js·ecmascript
EndingCoder4 小时前
React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用
前端·react.js·架构·前端框架
阿阳微客5 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏
德育处主任Pro6 小时前
『React』Fragment的用法及简写形式
前端·javascript·react.js
CodeBlossom6 小时前
javaweb -html -CSS
前端·javascript·html
CodeCraft Studio6 小时前
【案例分享】如何借助JS UI组件库DHTMLX Suite构建高效物联网IIoT平台
javascript·物联网·ui
打小就很皮...7 小时前
HBuilder 发行Android(apk包)全流程指南
前端·javascript·微信小程序
集成显卡8 小时前
PlayWright | 初识微软出品的 WEB 应用自动化测试框架
前端·chrome·测试工具·microsoft·自动化·edge浏览器