call | apply bind原生实现

本文详细比较了JavaScript的call()、apply()和bind()函数,阐述它们如何改变函数内部的this指向,以及在性能上的微妙差别。特别强调了bind函数的特性,以及原生bind实现的逻辑。
摘要由CSDN通过智能技术生成
前言

apply(thisArg, [])
call(thisSrg, arg1,arg2,...)
函数作用:改变this的指向
函数区别:功能完全一样,接收的参数形式不一样,但性能有些许差别
call比apply出来的早一些,而且在算法步骤中,apply多了CreateListFromArrayLike的调用,其他的操作几乎是一样的(甚至apply仍然多了点操作)。从草案的算法描述来看,call性能 > apply性能。参数大于3个,call>apply,小于则忽略不计。

call
Function.prototype.myCall = function (context = window) 
  let _context = context // 第一个参数不传默认为window
  _context.fn = this // 将foo作为target的私有方法, this改变
  const args = [...arguments].slice(1) // 截取下标从1开始的参数 {'param1', 'param2'}
  const result = _context.fn(...args) // 立即执行
  delete _context.fn // 删除fn 不改变target
  return result
}

apply
Function.prototype.myApply = function (context = window, arr) {
  let _context = context// 第一个参数不传默认为window
  _context.fn = this // 将fn作为target的私有方法, this改变
  const result = arr.length ? _context.fn(...arr) :     _context.fn() // 判断是否传入arr
  delete _context.fn // 删除fn 不改变target
  return result
}

bind

bind函数作用:改变this指向

注意一旦函数通过bind传递了有效的this对象,则该函数在运行期的this将指向这个对象,即使通过call或apply来试图改变this的指向也是徒劳的。

  • 作为普通函数时
function func(...arg){
    console.log(this);
    console.log(...arg);
}
func.prototype.con = function(){
    console.log('con');
};
let newFunc = func.bind({a: 1},1,2,3,4);
newFunc(); 
// 输出:
// { a: 1 }
// 1 2 3 4
  • 作为构造函数
function func(...arg){
    console.log(this);
    console.log(...arg);
}
func.prototype.con = function(){
    console.log('con');
};
let newFunc = func.bind({a: 1},1,2,3,4);
let fn = new newFunc();
// 输出:
// func {}
// 1 2 3 4

基于bind这些特性,来分析原生写bind

//原生实现bind
Function.prototype.myBind = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new Error("Type error");
  }
  // 获取参数
  const args = [...arguments].slice(1);
  const _this = this; // 保存this的值,代表调用bind的函数
  //返回一个函数,此函数可以被作为构造函数调用,也可以作为普通函数调用
  const Fn = function () {
    // 根据调用方式,传入不同绑定值
    // 当作为构造函数时,this 指向实例,不会被任何方式改变 this,要忽略传入的context上下文
    return _this.apply(
      this instanceof Fn ? this : context,
      // bind可以分开传递参数(如f.bind(obj, 1)(2)),所以需要将参数拼接,这里使用apply,参数拼接成一个数组
      args.concat(...arguments)//当前的这个 arguments 是指 Fn 的参数,也可以用剩余参数的方式
    );
  };
  //对于构造函数,要保证原函数的原型对象上的属性不能丢失
  Fn.prototype = Object.create(_this.prototype);
  return Fn;
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值