【JavaScript高级】手写apply()、call()、bind()

手写之前

我们有一个函数foo。
已知:

  • foo的隐式原型是绑定在Function的显式原型上的(Function是一个构造函数)
function foo(){}
console.log(foo.__proto__===Function.prototype);//true
  • apply、call、bind方法是来自Function的原型对象
console.log(Function.prototype.apply);//ƒ apply() { [native code] }
  • 也就是说:在Function的原型对象上添加的属性或方法, 可以被所有的函数获取

apply

获取thisArg, 我们要确保是一个对象类型,要进行边界判断

Function.prototype.MyApply = function(thisArg){
   thisArg=(thisArg===undefined||thisArg===null)?window:Object(thisArg);
};

将this绑定到传入的参数thisArg上

我们想实现apply显式绑定,就只能用:默认绑定、隐式绑定、new绑定来实现。(总不能自己实现自己)。

默认绑定肯定不是我们要的,因为显式绑定并不希望帮到window上。
隐式绑定可以。
new绑定要用到构造函数,略显复杂。

所以我们用隐式绑定

Function.prototype.MyApply = function(thisArg){
    thisArg=(thisArg===undefined||thisArg===null)?window:Object(thisArg);

    //这步
    //当读取thisArg.fn时返回this,相当于thisArg.fn=this
    //这里创建一个属性fn,它的值为this
    Object.defineProperty(thisArg,"fn",{
        configurable:true,//true,否则没法delete
        value:this,
    });

    //隐式绑定:让this指向thisArg
    thisArg.fn();

    //完成后删除thisArg中的fn属性
    delete thisArg.fn;
};

将剩余的其他参数传入thisArg

apply传入的其他参数是一个数组。

function foo(name, age) {
  console.log(this, name, age); // {name: 'kaisa'} 'kaisa' 18
}

Function.prototype.myapply = function (thisArg, arrArgs) {
  
  thisArg =thisArg === undefined || thisArg === null ? window : Object(thisArg);

  Object.defineProperty(thisArg, "fn", {
    configurable: true,
    value: this,
  });

  // 通过展开运算符, 将其他参数传入thisArg
  thisArg.fn(...arrArgs);

  delete thisArg.fn;
};

foo.myapply({ name: "kaisa" }, ["kaisa", 18]);

call

call传入的其他参数是参数列表

function foo(name, age) {
    console.log(this, name, age);
}

Function.prototype.MyCall = function (thisArg,...arrArgs) {
    thisArg = (thisArg === undefined || thisArg === null) ? window : Object(thisArg);

    Object.defineProperty(thisArg, "fn", {
        configurable: true,
        value: this,
    });
    
    thisArg.fn(...arrArgs);

    delete thisArg.fn;
};

foo.MyCall({name:"abc"},"abc", 18);

封装函数实现apply和call

显然,apply和call的函数有重复的代码。因此,我们可以把重复代码封装成一个函数。

function repFn(thisArg,otherArgs,fn){
    thisArg= (thisArg===null||thisArg===undefined)?window:Object(thisArg);

    Object.defineProperty(thisArg,"fn",{
        configurable: true,
        value: fn,
    })

    thisArg.fn(...otherArgs);

    delete thisArg.fn;
}

//apply
Function.prototype.MyApply=function(thisArg,otherArgs){
    repFn(thisArg,otherArgs,this);
}

//call
Function.prototype.MyCall=function(thisArg,...otherArgs){
    repFn(thisArg,otherArgs,this);
}

测试:

//测试
function foo1(name,age){
    console.log(this,name,age);
}

function foo2(name,age){
    console.log(this,name,age);
}

foo1.MyApply({name:"apply"},["apply",19]) //{name: 'apply', fn: ƒ} 'apply' 19
foo2.MyCall({name:"call"},"call",20)//{name: 'call', fn: ƒ} 'call' 20

bind

bind函数会返回一个新的函数,返回的新函数中可以传参数。

function foo(name,age,height){
    console.log(this,name,age,height);
}

Function.prototype.MyBind=function(thisArg,...otherArgs){
    thisArg= thisArg===null||thisArg===undefined?window:Object(thisArg);

    Object.defineProperty(thisArg,"fn",{
        configurable:true,
        value:this
    })

    return (...newArgs) =>{
        var allArgs=[...otherArgs,...newArgs];
        thisArg.fn(...allArgs);
    };
};

var newFoo=foo.MyBind({name:"bind"},"bind");
newFoo(18,1.88);//{name: 'bind', fn: ƒ} 'bind' 18 1.88

参考

coderwhy的课
手写apply-call-bind
手写 实现call、apply和bind方法 超详细!!!
使用JS简单实现一下apply、call和bind方法
Function

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

karshey

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

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

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

打赏作者

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

抵扣说明:

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

余额充值