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

相关推荐
毛骗导演3 分钟前
Skill 还是 Tool?——从 OpenClaw 源码看 Agent 能力扩展的两种范式
前端·架构
周杰伦fans8 分钟前
禁止edge浏览器更新
前端·edge
user2975258761213 分钟前
使用SSE实现流式渲染实践
前端·javascript
LPieces14 分钟前
【LPieces-UI】02-Icon组件的设计与实现
前端·vue.js
我本地是好的15 分钟前
解决高德地图无外网访问难题:Vue项目代理转发全攻略
前端
折哥的程序人生 · 物流技术专研16 分钟前
《Java 100 天进阶之路》第14篇:Java final关键字详解
java·开发语言·后端·面试
IT当时语_青山师__JAVA技术栈17 分钟前
数组与链表深度解析:从内存布局到工业级实践
java·算法·面试
学习论之费曼学习法17 分钟前
AI 入门 30 天挑战 - Day 29 - 面试准备指南
人工智能·面试·职场和发展
wand codemonkey18 分钟前
Maven Web 项目 + Tomcat 从零排错全流程(零遗漏版)
前端·tomcat·maven
笨鸟先飞的橘猫25 分钟前
基于Skynet的分布式游戏场景题:大型MMO的跨服战场系统设计
分布式·学习·游戏·面试·lua