手撕实现call函数

手撕实现Call函数

简单分析一下要实现的功能

 function test(a,b){
    console.log(this,a,b)
    return a + b
}
test.call({},1,2)

//输出 {} 1 2

利用基础知识实现最简单的call函数

首先我们都知道,call函数是写在Function的原型中的,所以我们也要将自己的call函数,下面叫他myCall函数吧,也写在原型中

Function.prototype.myCall = function(){

}

我们的myCall需要接收两类参数,一类是需要将this指向的对象,另一个是携带的参数。这里我们需要使用到我们ES6的方法,将参数分成两类

Function.prototype.myCall = function(thatObj,...args){
    //前者是this要指向的对象,后者是携带的参数
}

ok下面我们就继续改造myCall

因为myCall是Function的原型函数,当我们用函数调用他时,他的this指向的是调用他的函数,所以我们可以为要指向的对象中添加一个属性保存原函数,这样,我们就可以改变this的指向啦

Function.prototype.myCall = function(thatObj,...args){
    thatObj.fn = this
    thatObj.fn(...args) //此时就将原函数的this指向了thatObj这个新对象,并将携带的参数传递回给原函数
    //因为我们创建了新的属性,所以我们要将他删除
    delete thatObj.fn
}

一个最简单的myCall就写好了

解决属性名重复和隐式的问题

因为thatObj.fn的属性容易发生重名,即使属性名再复杂,也有重名的可能嘛。这时要利用我们ES6的Symbol来解决这个问题了

Function.prototype.myCall = function(thatObj,...args){
    let key = Symbol('temp')
    Object.defineProperties(thatObj,key,{
        enumerable:true,
        value:this
    }) 
    console.log(thatObj)
    let result = thatObj[key](...args) //因为有可能有返回值,我们还要保留这个返回值后,再返回
    delete thatObj.fn
    return result
}

解决传进来的为null和undefined的问题

当我们传入的thatObj是null或者undefined时,我们将this指向window,但随着前端的发展,全局对象不只局限于浏览器了,同时还出现了Node的技术,所以我们将this指向globalThis。其余的我们用Object封装一下thatObj,防止他是Number等基础数据类型

Function.prototype.myCall = function(thatObj,...args){
    thatObj = (thatObj === null || thatObj === undefined)?globalThis:Object(thatObj) 
    let key = Symbol('temp')
    Object.defineProperties(thatObj,key,{
        enumerable:true,
        value:this
    })
    console.log(thatObj)
    let result = thatObj[key](...args)
    delete thatObj.fn
    return result
}

完成体

function test(a,b){
    console.log(this,a,b)
    return a + b
}
test.call({},1,2)
Function.prototype.myCall = function(thatObj,...args){
    thatObj = (thatObj === null || thatObj === undefined)?globalThis:Object(thatObj)
    let key = Symbol('temp')
    Object.defineProperties(thatObj,key,{
        enumerable:true,
        value:this
    })
    console.log(thatObj)
    let result = thatObj[key](...args)
    delete thatObj.fn
    return result
}
test.myCall({},2,3)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

傅里叶级数ff

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值