call()、apply() 和 bind()

call() 和 apply() 作用类似,call() 和 apply() 方法的区别在于其传递参数的格式不同,一个是参数列表,一个是数组。

func.call(thisArg, arg1, arg2, ...)
func.apply(thisArg, [arg1, arg2, ...]) 

传递参数并非 call() 和 apply() 真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域,来个栗子

 let v1 = {
      name: 'xxx'
    };
    
 let v2 = {
      name: 'bbb'
    };

 function f(val) {
      console.log(this.name, val);
    }

    f.call(v1, 'v1'); // 输出 xxx  v1
    f.apply(v2, ['v2']); // 输出 bbb  v2

通过传入 对象,使 f() 方法中的this指向了传入的对象,所以最后输出了 name的值。

bind() 方法,这个方法会创建一个函数的实例,其 this 值会被绑定到传递给 bind() 函数的值(也就是第一个参数)。

  let v3 = {
      name: 'aaa'
    };
 function f(val) {
      console.log(this.name, val);
      // console.log(arguments);  可以查看传进来的参数
    }
 f.bind(v3, 'v3'); // 没有输出

 var s = f.bind(v3, 'v3');
    s('v33'); // 输出 aaa  v3  arguments里面可以查看到传进去的v33

手写call


// 手写call()方法  thisArg 就是要绑定的那个this
Function.prototype.myCall = function(thisArg, ...args) {
   // 将 thisArg 转成对象类型(防止它传入的是非对象类型,例如123数字)
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
    thisArg.fn = this; // this指向调用call的对象,即我们要改变this指向的函数
    const result = thisArg.fn(...args);
    delete thisArg.fn;
    return  result; // 执行函数并return其执行结果
}

手写apply


// 手写实现apply方法
Function.prototype.myApply = function(thisArg, args) {
//Symbol只是标记一块内存,不能与其他数据类型进行运算
    var fn = Symbol('fn');        // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
    thisArg = thisArg || window;    // 若没有传入this, 默认绑定window对象
    thisArg[fn] = this;              // this指向调用apply的对象,即我们要改变this指向的函数
    var newArgs = args ? args : [];  // 这里判断是否传递了参数
    var result = thisArg[fn](...newArgs);  // 执行当前函数(此处说明一下:虽然apply()接收的是一个数组,
    // 但在调用原函数时,依然要展开参数数组。可以对照原生apply(),原函数接收到展开的参数数组)
    delete thisArg[fn];              // 删除我们声明的fn属性
    return result                  // 返回函数执行结果
}

手写bind


// 手写bind
Function.prototype.myBind = function(...rest1) {
    var self = this
    var context = rest1.shift() // 取得第一个参数(即执行环境),并删除
    return function(...rest2) {
        return self.apply(context, [...rest1, ...rest2])
    }
}

// 第二种
Function.prototype._call = function(thisArg,...args){
    fn = this
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
 
    thisArg.fn = fn
    let result = thisArg.fn(...args)
    delete thisArg.fn
 
    return result
}
 
// 利用 _call 模拟 bind
Function.prototype._bind = function(thisArg,...args){
    let fn = this // 需要调用的那个函数的引用
    // bind 需要返回一个函数
    return function(){
        return fn._call(thisArg, ...args)
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值