原生JavaScript重写call方法详解(不使用bind、apply做辅助)

众所周知,call方法是用来改变函数(方法)的this指向,并且返回函数调用的返回值,下面将详细讲解call方法的重写,并且优化。

知道Function.prototype.call()的作用之后,我们可以使用JavaScript基础知识来重写

1. 首先call方法是Function的公用方法,并且可以传入多个参数,第一个参数是改变的this指向,剩下的参数是函数被调用所传入的参数;

// 此处第二个参数用到es6的展开语法
Function.prototype.MyCall = function (point, ...arg) {}

2. 函数的this指向是指向调用它的“对象”,所以MyCall方法中的this就是调用MyCall方法的函数

Function.prototype.MyCall = function (point, ...arg) {
    console.log(this) // --->ƒ fn () {}
}
functionfn () {}

fn.MyCall()

3. 实现call方法自动调用函数并且返回调用结果

Function.prototype.MyCall = function (point, ...arg) {
    const result = this(...arg) // 此时的this就是调用MyCall方法的函数,所以this()就是调用fn函数
    return result
}
function fn (...arg) {
    let res = [...arg]
    return res
}

fn.MyCall({},1,2,3)

函数运行结果:

4. 此时我们需要考虑给函数更改this指向

同第二步一样,需要将fn函数的this指向“什么”,就用“什么”去调用fn函数

Function.prototype.MyCall = function (point, ...arg) {
    // 将fn函数挂载到需要改变的this指向对象上的随便一个属性上(下面用的是"key")
    point.key = this// 然后调用函数去改变this指向到“point”对象上
    const result = point.key(...arg)
    // 删除无用的属性
    delete point.key
    return result
}
function fn (...arg) {
    console.log(this)
    let res = [...arg]
    return res
}

fn.MyCall({},1,2,3)

调用结果: 可以看到fn函数中打印的this已经指向了一个对象。

5. 优化可修改的this指向(MyCall方法的第一个参数)

当我们再给第一个参数传入null 或者 undefined时,call方法会将this指向改为全局,否则会指向一个相应的数据类型

Function.prototype.MyCall = function (point, ...arg) {
    // 判断point类型// globalThis 表示全局对象 因为JavaScript运行环境不同,不可以写window。
    point = point === null || point === undefined ? globalThis : Object(point) 
    point.key = this
    const result = point.key(...arg)
    delete point.key
    return result
}
function fn (...arg) {
    console.log(this)
    let res = [...arg]
    return res
}

fn.MyCall({},1,2,3)

6. 优化自定义属性“key”

上文中我们的随机属性命名为“key”,为了防止属性名重复我们也可以设置一个比较“变态的属性名” 例如:"xxx"、"aaa"等等此时我们可以用到es6中的symbol来创建一个唯一的属性名

Function.prototype.MyCall = function (point, ...arg) {
    point = point === null || point === undefined ? globalThis : Object(point) 
    const key = Symbol("key")
    point[key] = this
    const result = point[key](...arg)
    delete point[key]
    return result
}

此时,MyCall方法在不通过apply或者bind辅助时实现了。

如有发现不合适的地方,虚心接受大佬们的指点。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值