JavaScript基础之call、apply和bind方法

JavaScript中函数原型方法call、apply和bind

call、apply、bind方法主要用来改变函数中this的指向(显式绑定this)

1. call

调用call方法会将函数中的this指向上下文对象,然后传递call中余下的参数给函数,并执行函数。

Function.prototype(context, …rest)。

  • call方法的第一个参数为一个上下文对象,也就是绑定this的对象,对于基本类型string、number、boolean等类型,会将其转化为相对应的基本包装类型,而对于undefined或者null会将上下文对象指向全局对象(浏览器中为window,Node中为global);
  • 后续的参数是是传递给调用call方法的参数列表;
  • 要想函数this指向某个对象,那么直接将函数赋值给那个对象的属性。
function getGlobalThis () {
  return this
}

// ES3
Function.prototype.call = function (context) {
  context = context == null ? getGlobalThis() : Object(context)
  context._fn = this // this为调用call方法的函数实例
  var args = []
  for (var i = 1; i < arguments.length; i++) {
    args.push('arguments['+ i + ']')
  }
  var res = eval('context._fn(' + args +')')
  delete context._fn
  return res
}

// ES6
Function.prototype.call = function (context, ...rest) {
  context = context == null ? getGlobalThis() : Object(context)
  const _fn = Symbol('_fn')
  context[fn] = this
  const res = context[_fn](...rest)
  delete context[_fn]
  return res
}

2. apply

apply方法与call方法基本类似,惟一的区别就是,后续参数的不同,apply方法只接受两个参数,第二个为传递给函数的参数列表的数组或者arguments对象。

function getGlobalThis () {
  return this
}

// ES3
Function.prototype.apply = function (context, args) {
  context = context == null ? getGlobalThis() : Object(context)
  context._fn = this
  var res
  if (args == undefined) {
  	res = context._fn()  
  } else if (typeof args !== 'object') { // 支持arguments
    throw new TypeError('CreateListFromArrayLike called on none-object')
  } else {
    args = Array.prototype.slice.call(args) // 将arguments转化为数组
    res = eval('context._fn('+ args + ')')
  }
  delete context._fn
  return res
}

// ES6
Function.prototype.apply = function (context, args) {
  context = context == null ? getGlobalThis() : Object(context)
  const _fn = Symbol('_fn')
  var res
  if (typeof args !== 'object' && args !== null) {
    throw new TypeError('CreateListFromArayLike called on none-object')
  } else {
    res = context[_fn](...args)
  }
  delete context[_fn]
  return res
}

3. bind

bind方法与前两个方法有所不同;bind方法会将调用它的函数中的this绑定为第一个参数(上下文对象),然后保存接下来的参数列表,最后返回一个新的函数,新的函数name名为bound + 原函数名,并且bound的prototype继承自原函数的prototype。

  • 第一个参数与call和apply方法一致;
  • 后续参数为参数列表;
  • 返回一个新的函数bound,会把传递给bound的参数列表与原来的参数列表进行合并(函数柯里化)
  • 调用bound函数后会判断bound是以new操作符调用还是一般调用,如果是new方法调用(即调用bound方法中this在bound的作用域链上),那么将context设置为this。
  • bound函数的name属性为[bound + 原函数名],bound的prototype继承自原函数的prototype
function getGlobalThis () {
  return this
}

Function.prototype.bind = function (context) {
  context = context == null ? getGlobalThis() : Object(context)
  var that = this
  var args = Array.prototype.slice.call(arguments, 1)
  function bound () {
    var innerArgs = Array.prototype.slice.call(arguments)
    context = this instanceof bound ? this : context
    var res = that.apply(context, args.concat(innerArgs))
    return res
  }
  function F () {}
  F.prototype = that.prototype
  bound.__proto__ = new F()
  Object.defineProperties(bound, {
    name: {
      configurable: true,
      enumerable: false,
      writable: false,
      value: 'bound' + that.name
    }
  })
  return bound
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值