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)
全部评论

相关推荐

找工作勤劳小蜜蜂:自我描述部分太差,完全看不出想从事什么行业什么岗位,也看不出想在哪个地区发展,这样 会让HR很犹豫,从而把你简历否决掉。现在企业都很注重员工稳定性和专注性,特别对于热爱本行业的员工。 你实习的工作又太传统的it开发(老旧),这部分公司已经趋于被淘汰,新兴的互联网服务业,比如物流,电商,新传媒,游戏开发和传统的It开发有天然区别。不是说传统It开发不行,而是就业岗位太少,基本趋于饱和,很多老骨头还能坚持,不需要新血液。 工作区域(比如长三角,珠三角,成渝)等也是HR考虑的因素之一,也是要你有个坚定的决心。否则去几天,人跑了,HR会被用人单位骂死。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务