js手撕this绑定--模拟call函数的实现

第一印--模拟call函数的实现:
第一步我们向所有函数父类的原型上也就是window的Function属性原型上添加模仿的call函数
window中的属性

//Function原型上添加模仿的call函数
Function.prototype.imicall=function (){
    console.log("模拟call:");
    //这里面的this就是sum这个函数
    let fn=this
    fn()
}
function sum(){
   console.log("i am sum:",this);
}
sum.imicall()

第一步执行结果
第二步尝试用隐式绑定把函数引用的this绑定到指定传入的对象上(简单实现)

Function.prototype.imicall=function (flag){
    console.log("模拟call:");
    let fn=this
    flag.fn=fn
    flag.fn()
    delete flag.fn
}
function sum(){
   console.log("i am sum:",this);
}
var obj={name:'xwl'}
sum.imicall(obj)

第二步执行结果
第三步考虑边界(绑定对象的选值情况)--进一步完善this绑定
首先要知道通过call函数绑定的this类型最后都为object

function test(){
    console.log(typeof this);
    console.log(this);
    console.log("i am test");
}
test.call(123)

类型说明
接下来考虑下null和undefined如何处理
我们先来看下结果
空处理
可以看到都是window,至于转换成对象,这个简单,直接用Object包裹就可以了
所以思路如下:如果flag有值且不为空那么就用Object包裹,否则就赋为window

Function.prototype.imicall=function (flag){
    console.log("模拟call:");
     if(flag!==0){
         flag=flag?Object(flag):window
     }else{
         flag=Object(flag)
     }
    let fn=this
    flag.fn=fn
    flag.fn()
    delete flag.fn
}
function sum(){
   console.log("i am sum:",this);
}
var obj={name:'xwl'}
sum.imicall(obj)

接下来我们来测试下好使不

Function.prototype.imicall=function (flag){
    console.log("模拟call:");
     if(flag!==0){
         flag=flag?Object(flag):window
     }else{
         flag=Object(flag)
     }
    let fn=this
    flag.fn=fn
    flag.fn()
    delete flag.fn
}
function sum(){
   console.log("i am sum:",this);
}
var obj={name:'xwl'}
sum.imicall(obj)
sum.imicall(null)
sum.imicall(undefined)
sum.imicall()

测试结果
第四步解决参数传递问题
首先想到的是我们能不能用函数自带的保存参数的arguments来做

Function.prototype.imicall=function (flag){
    console.log("模拟call:");
    console.log(arguments);
     if(flag!==0){
         flag=flag?Object(flag):window
     }else{
         flag=Object(flag)
     }
    let fn=this
    flag.fn=fn
    flag.fn()
    delete flag.fn
}
function sum(num1,num2){
   console.log("i am sum:",this);
   console.log(num1+num2);
}
var obj={name:'xwl'}
sum.imicall(obj,1,2)

接收结果
所以我们把下标从1开始的元素推到新的数组里,再将数组展开放到执行函数参数中

Function.prototype.imicall=function (flag){
    console.log("模拟call:");
    let args=[]
    for(var i=1;i<arguments.length;i++){
        args.push(arguments[i])
    }
     if(flag!==0){
         flag=flag?Object(flag):window
     }else{
         flag=Object(flag)
     }
    let fn=this
    flag.fn=fn
    flag.fn(...args)
    delete flag.fn
}
function sum(num1,num2){
   console.log("i am sum:",this);
   console.log(num1+num2);
}
var obj={name:'xwl'}
sum.imicall(obj,1,2)

args执行结果
感觉有点麻烦对吗?
那就用es6,需要注意的是如果我们向flag后面添加个新的参数,并对其展开,那么它会是什么?
展开类型
欸嘿,它直接就是数组,那就好办了,底下直接展开不就完事了!
展开结果
第五步别家函数都可以显示返回值,你不也得搞一个!

Function.prototype.imicall=function (flag,...args){
    console.log("模拟call:");
     if(flag!==0){
         flag=flag?Object(flag):window
     }else{
         flag=Object(flag)
     }
    let fn=this
    flag.fn=fn
    var result=flag.fn(...args)
    console.log(result);
    delete flag.fn
    return result
}
function sum(num1,num2){
   console.log("i am sum:",this);
//    console.log(num1+num2);
   return num1+num2
}
var obj={name:'xwl'}
var res=sum.imicall(obj,1,2)
console.log(res);

返回值
最后一步完整版

Function.prototype.imicall=function (flag,...args){
    console.log("模拟call:");
     if(flag!==0){
         flag=flag?Object(flag):window
     }else{
         flag=Object(flag)
     }
    let fn=this
    flag.fn=fn
    var result=flag.fn(...args)
    delete flag.fn
    return result
}
function sum(num1,num2){
   console.log("i am sum:",this);
   return num1+num2
}
var obj={name:'xwl'}
var res=sum.imicall(obj,1,2)
全部评论

相关推荐

不愿透露姓名的神秘牛友
10-05 10:13
已编辑
HHHHaos:让这些老登来现在秋招一下,简历都过不去
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务