手动实现call(), apply(), bind()

2,461 阅读2分钟

一、call、apply、bind 其作用都是改变函数运行时this的指向

1, call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔   
2, apply 的所有参数都必须放在一个数组里面传进去  
3, bind 除了返回是函数以外,它 的参数和 call 一样

二、手动实现三个函数

1, 回忆

1, 每个 JavaScript 函数实际上都是一个 Function 对象
   console.log((function(){}).constructor === Function)
2, javascript的fn方法
   对应JQuery: 
   jQuery.extend(object); 为扩展jQuery类本身.为类添加新的方法。
   jQuery.fn.extend(object);给jQuery对象添加方法。
   可以理解为:jQuery.fn = jQuery.prototype

2,call 函数实现

Function.prototype.myCall = function(context) {
  // 首先判断调用对象
  if(typeof this !== 'function') {
    console.log('type error')
  }
  // 获取参数
  let args = [...arguments].slice(1); //第一个是对象,从第二个开始
  result = null
  // 判断content(this指针要指向的对象)是否传入, 如果没有设置为window
  context = context || window
  // 将调用函数设置为对象的方法
  context.fn = this
  // 调用函数
  result = context.fn(...args);
  // 删除属性
  delete context.fn
  return result
}

3, apply函数实现

Function.prototype.myApply = function (context) {
  // 首先判断调用对象是否为函数
  if(typeof this !== 'function') {
    throw new TypeError('error')
  }
  let result = null
  // 判断传入的对象是否存在,在浏览器中默认是window, 在node.js中默认是Object
  context = context || window
  // 把当前调用的函数赋值给传入对象的
  // context.fn 可以理解为: context.prototype.
  context.fn = this
  if (arguments[1]) {
    result = context.fn([...arguments[1]]) // 调用赋值的函数
  }
  delete context.fn
  return result
}

4, bind函数实现

Function.prototype.myBind = function(context) {
  if (typeof this !== 'function') {
    throw new TypeError('error')
  }
  // 获取参数
  let args = [...arguments].slice(1) // 第一个是对象
  context.fn = this // 调用对象
  return function Fn() {
    return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments))
  }
}

5, 测试

var cat = {
  name:"喵喵",
  eatFish:function(param1,param2){
    console.log("吃鱼");
	  console.log("this的指向=>");
	  console.log(this);
  	console.log(param1,param2);
  }
}
var dog = {
	name:"汪汪",
	eatBone:function(param1,param2){
		console.log("啃骨头");
		console.log("this的指向=>");
		console.log(this);
		console.log(param1,param2)
	}
}
cat.eatFish.myCall(dog,'汪汪','吃鱼,call')
cat.eatFish.myApply(dog,['汪汪','吃鱼,apply'])
let eatFun = cat.eatFish.myBind(dog,'汪汪','吃鱼','bind')
    console.log(eatFun())

三, 总结

bind和call与apply的区别是不会立即调用函数,常用于改变回调函数的参数,bind的参数传递方式和call一样 箭头函数体内的 this 对象, 是定义时所在的对象, 而不是使用时所在的对象