分别手写一个bind call apply 函数

本文已同步:个人博客地址


前言

最近复习ES6时经常遇到这三个函数,发现用途很大,在尾递归,克隆方面都能用到,所以查询网上的资料后,准备好好复习复习


一、bind,call,apply的区别?

call 和 apply 都是为了解决改变 this 的指向。作⽤都是相同的,只是传参的⽅式 不同。 除了第⼀个参数外, call 可以接收⼀个参数列表, apply 只接受⼀个参数数组。bind 和其他两个⽅法作⽤也是⼀致的,只是该⽅法会返回⼀个函数。并且我 们可以通过 bind 实现柯⾥化

二、手写实现这三个函数

1.手写call

代码是背了别人的 再自己写的,这里主要是讲解保准你能动

代码如下(示例):

Function.prototype.myCall = function (context) {
    debugger
    var context = context || window  //context赋值为传入来的对象
    // console.log(context);

    // console.log(this); //一开始的this是指向要调用的那个函数的
    context.fn = this  // 这里是将这个函数归纳到context对象里面
    // console.log(context.fn);

    // console.log(arguments);
    var args = [...arguments].slice(1) //去后面列表的参数
    // console.log(args);

    var result = context.fn(...args) //调用这个函数
    // console.log(result);

    delete context.fn
    return result

}

let a = {
    value: 1
}
function getValue(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value)
}
getValue.myCall(a, 'zhangshan', '12')

为了方便,我直接把执行过程的一些东西打印了出来
在这里插入图片描述
上面 是这个函数的执行过程,一目了然了

  • 一开始传入进来的context 就是赋值为 a 这个对象了
  • 因为是这个getValue.myCall(a, ‘zhangshan’, ‘12’)函数调用的,所以call里面的this是指向这个函数的
  • 后面的将this赋值给context.fn 实际上context.fn 就是将这个函数了
  • 所以最终context对象就变成了{value:1,fn:f}这样
  • 最终再调用一下这个函数

建议你看懂了自己写一下 apply

2.手写apply

下面是我自己写的,我自己试了一下是可以的,如有不对还请指正
代码如下(示例):

Function.prototype.myApply = function(obj){
    var obj = obj || window
    // console.log(this);
    obj.fn = this
    // console.log(obj);
    // console.log(arguments);
    var args = [...arguments].slice(1)
    // console.log(...args.flat());
    var res = obj.fn(...args.flat())
    delete obj.fn 
    return res
    
}

let a = {
    value: 1
}
function getValue(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value)
}
getValue.myApply(a, ['zhangshan', '12'])

3.手写bind

区别不大,但是有一点是需要注意的:return function fn 返回了个函数是闭包

Function.prototype.myBind = function(obj){
    if(typeof this !== 'function'){
        throw new TypeError('Error')
    }
    var _this = this 
    console.log(_this);
    var args = [...arguments].slice(1)
    console.log(args);

    return function fn(){
    // 如果this 是fn的实例
        if(this instanceof fn){
            return new _this(...args,...arguments)
        }
        return _this.apply(obj,args.concat(...arguments))
    }
}

this.x = 9;    // 在浏览器中,this 指向全局的 "window" 对象
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
console.log(retrieveX());
// 返回 9 - 因为函数是在全局作用域中调用的

// 创建一个新函数,把 'this' 绑定到 module 对象
// 新手可能会将全局变量 x 与 module 的属性 x 混淆
var boundGetX = retrieveX.myBind(mduole);
 // 81
console.log(boundGetX());

总结

反复看,反复写,才能记住的

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值