# apply bind call 用法

call、apply和bind是 Function对象 自带的三个方法,都是为了 改变函数体内部this指向 。三者第一个参数都是 this 要指向的对象,也就是想指定的上下文;apply 、 call 、bind 三者都可以利用后续参数传参;bind是返回对应函数,便于调用;apply 、call 则是立即调用

# bind

	function.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg:调用绑定函数时作为this参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用bind在setTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object。如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg。

# call apply

	var name="wang",age=17;
	var obj={
	    name:"zhang",
	    objage:this.age,
	    myFun:function(){
	        console.log(this.name+"年齡"+this.age)
	    }
	}
	console.log(obj.objage) // 17
	console.log(obj.myFun()) //zhang年齡undefined 需要办法改变this指向
var name="wang",age=17;
var obj={
	name:"zhang",
	objage:this.age,
	myFun:function(from,go){
		console.log(this.name+"年齡"+this.age,"来自"+from+"去"+go)
	}
}
var k1={
	name:"k1",
	age:18
}

console.log(obj.myFun.bind(k1)('上海','芜湖')) //k1年齡18 来自上海去芜湖
console.log(obj.myFun.call(k1,'上海','芜湖')) //k1年齡18 来自上海去芜湖
console.log(obj.myFun.apply(k1,['上海','芜湖'])) //k1年齡18 来自上海去芜湖
- 描述
call 立即调用;后面第一个参数为对应指向的对象;随后的参数均为调用函数的参数。
apply 立即调用;第一个参数同上,随后的参数均写入一个数组作为参数。
bind 给出函数,需另外调用,第一个参数同上。

# 手写apply,call,bind

call/apply/bind的核心理念:借。

借助已实现的方法,改变方法中数据的this指向,减少重复代码,节省内存。

Function.prototype.myCall = function(context) {
		  console.log(this) //fn a()
		  if (typeof this !== 'function') {
			throw new TypeError('Error')
		  }
		  context = context || window
		  console.log(context)//obj
		  context.fn = this
		  console.log(typeof context.fn)//function
		  
		  const args = [...arguments].slice(1)
		  console.log(args)
		  //通过隐式绑定的方式调用函数
		  const result = context.fn(...args)
		   //删除添加的属性
		  delete context.fn
		   //返回函数调用的返回值
		  return result
}

let obj ={
	name:333
}

function a(){
	console.log(this.name)
}
a.myCall(obj)
Function.prototype.myApply = function(context) {
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  context = context || window
  context.fn = this
  let result
  // 处理参数和 call 有区别
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }
  delete context.fn
  return result
}

如果怕重复key值(fn),可以使用Symbol

/**
 * 自定义call实现
 * @param context   上下文this对象
 * @param args      动态参数
 */
Function.prototype.ownCall = function(context, ...args) {
  context = (typeof context === 'object' ? context : window)
  // 防止覆盖掉原有属性
  const key = Symbol()
  // 这里的this为需要执行的方法
  context[key] = this
  // 方法执行
  const result = context[key](...args)
  delete context[key]
  return result
}

注意bind的用法,bind可以分批添加参数,所以需要拼接,而且bind返回的是函数,考虑兼容new的情形。

Function.prototype.myBind = function(context, ...args) {  
	  const originalFunction = this;  
	  
	  // 返回一个新函数  
	  return function F(...boundArgs) {  
	    // 如果通过 new 调用,则忽略 context,使用新创建的实例  
	    if (this instanceof F) {  
	      // 相当于执行 new originalFunction(...args, ...boundArgs)  
	      return new originalFunction(...args, ...boundArgs);  
	    }  
	  
	    // 否则,使用提供的 context 和合并的参数调用原函数  
	    return originalFunction.apply(context, args.concat(boundArgs));  
	  };  
	};  
	  
	// 使用示例  
	function MyConstructor(a, b) {  
	  this.a = a;  
	  this.b = b;  
	}  
	  
	MyConstructor.prototype.getValue = function() {  
	  return this.a + this.b;  
	};  
	  
	const boundConstructor = MyConstructor.myBind(null, 1);  
	  
	// 使用 new 调用 boundConstructor  
	const instance = new boundConstructor(2);  
	console.log(instance.getValue()); // 输出 3  
	  
	// 普通函数调用  
	const result = boundConstructor(3);  
	console.log(result); // 输出 MyConstructor 的返回值,如果没有显式返回,则为 undefined
最后更新: 4/15/2024, 4:08:25 PM