call,apply,bind

  • 都是用来改变 this指向的;第一个参数都是 this 要指向的对象,也就是想指定的上下文;
  • call和apply是直接执行函数。call的第二部分参数要一个一个传,apply要把这些参数放到数组中;
  • bind 返回的是一个新的函数,你必须调用它才会被执行。
function Fruits() {}

Fruits.prototype = {
  color: 'red',
  getColor: function() {
    return 'color is' + this.color
  }
}
var apple = new Fruits()
apple.getColor()	// color is red
var banana = {
  color: 'yellow'
}

apply.getColor.call(banana)	// color is yellow
apply.getColor.apply(banana)	// color is yellow
//  所以,可以看出 call 和 apply 是为了动态改变 this 而出现的,当一个 object 没有某个方法(本栗子中banana没有say方法),
但是其他的有(本栗子中apple有say方法),我们可以借助call或apply用其它对象的方法来操作

// 实例:
var  numbers = [5, 458 , 120 , -215]
Math.max.apply(null, numbers)	// 458
Math.min.call(null, 5, 458 , 120 , -215)	// -215

// 面试题
定义一个 log 方法,让它可以代理 console.log 方法,常见的解决方法是:
function log(){
  console.log.apply(null, arguments)
}
log(1, 'www', '&&&')	// 1 "www" "&&&"

// 进阶:开头加上(app)
function log(){
  var args = Array.prototype.slice.call(arguments)	// 需要将伪数组转化为标准数组
	args.unshift('(app)')
	console.log.apply(null, args)
}
log(1, '***')	// (app) 1 ***

// --- bind:
var a = document.write
// this指向global或window对象
a('test')	// Uncaught TypeError: Illegal invocation	
a.bind(document)('test')	// success

// 伪数组转化为标准数组
1、 Array.prototype.slice.call(arguments)
2、
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(slice)
slice(arguments)	// arguments转换成了标准数组

// 多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,
第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

代码实现

// call
Function.prototype.newCall = function (context, ...parameter) {
  if (typeof context === 'object') {
    context = context || window
  } else {
    context = Object.create(null)
  }
  let fn = Symbol()
  context.fn = this
  context.fn(...parameter)
  delete context.fn
}

// apply
Function.prototype.newApply = function (context, parameter) {
  if (typeof context === 'object') {
    context = context || window
  } else {
    context = Object.create(null)
  }
  let fn = Symbol()
  context.fn = this
  context.fn(...parameter)
  delete context.fn
}

// bind
Function.prototype.newBind = function (context, ...parameter) {
  let me = this
  return function(...argus) {
    return me.call(context, ...parameter, ...argus)
  }
}

// test
let person = {
  name: 'xyz'
}
function say (age, height) {
  console.log(this.name, age, height)
}
// test newCall
say.newCall(person, 25, 170)	// xyz 25 170

// test newApply
say.newApply(person, [25, 170])	// xyz 25 170

// test newBind
let bindSay = say.newBind(person, 25)
bindSay(170)	// xyz 25 170
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值