(十六)call、apply、bind介绍、区别和实现

函数中的this指向:

函数中的this指向是在函数被调用的时候确定的,也就是执行上下文被创建时确定的。在一个执行上下文中,this由调用者 提供,由调用函数的方式来决定。

类数组对象arguments:

arguments只在函数(除了箭头函数)中存在的类数组参数对象,储存了我们传入的所有参数。

一、call

  • call(this, 参1, 参2, ...),第一个参数为this,后面是函数的一系列参数
  • 当第一个this参数为null、undefind时,默认this指向window
  • 函数立即调用
  • 原理:实际就是把函数放到call传入的第一个参数上,然后再调用该函数。
  • 实现:
javascript 复制代码
/**
 * 手写call
 * @param {*} context
 * @param  {...any} args
 * @returns
 */
Function.prototype.mycall = function (context, ...args) {
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  //context不传,默认window
  let _this = context || window;

  //假如原来的context上存在fn属性会产生冲突,暂存一下。
  let temp = null;
  if (_this.fn) {
    temp = _this.fn;
  }

  _this.fn = this;
  // 调用函数
  let res = _this.fn(...args);

  if (temp) {
    //恢复_this对象上的原来的fn属性
    _this.fn = temp;
  } else {
    //删除_this对象上的fn属性
    delete _this.fn;
  }

  return res;

// 测试
let num = 1;
let obj = {
  num: 2,
  fn: "this is obj.fn",
};
function test(a, b, c, d) {
  let num = 1;
  console.log(this.num, "test参数", a, b, c, d);
}
test(4, 3, 2, 1);
// 调用myCall函数
test.mycall(obj, 4, 3, 2, 1);

// 检查obj本身的fn是否被修改
console.log(obj.fn);
};

二、apply

  • applyl(this, arr),第一个参数为this,第二个参数是一个参数数组
  • 当第一个this参数为null、undefind时,默认this指向window
  • 函数立即调用
  • 原理:和call类似,区别就是参数不同,call方法接受的参数是一个参数列表,而apply接受的是一个包含多个参数的数组。
  • 实现:
javascript 复制代码
// 和myCall的不同之处1:参数
Function.prototype.myApply=function(context){
  	if(typeof this!== 'function'){
        throw new TypeError('type error')
    }
  	console.log("myApply", arguments, context, this);
  	let _this = context || window;

  	let temp = null;
  	if (_this.fn) {
    	temp = _this.fn;
  	}
  	_this.fn = this;
  	let res;
  	//   判断是否存在第二个参数
  	if (arguments[1]) {
    	res = _this.fn(...arguments[1]);
  	} else {
    	res = _this.fn();
  	}
 // 删除context对象上的fn属性
  	if (temp) {
    	_this.fn = temp;
  	} else {
    	delete _this.fn;
  	}
 	 return res;
}

// 测试
let num = 1;
let obj = {
  num: 2,
  fn: "this is obj.fn",
};
function test(a, b, c, d) {
  let num = 1;
  console.log(this.num, "test参数", a, b, c, d);
}
test(4, 3, 2, 1);
// 调用myCall函数
test.myApply(obj, [4, 3, 2, 1]);

// 检查obj本身的fn是否被修改
console.log(obj.fn);

结果:

三、bind

  • bind(this, 参1, 参2, ...),第一个参数为this,后面是函数的一系列参数
  • 当第一个this参数为null、undefind时,默认this指向window
  • bind方法的返回值是函数,不会立即调用
  • 原理:(1)bind返回的函数作为构造函数使用的时候,bind绑定的this会失效,到那时参数有效。(2)如何判断bind 是正常使用还是当构造函数,根据this。当为构造函数时,this指向实例对象(this的prototype在该构造函数上)
  • 实现:
javascript 复制代码
Function.prototype.myBind = function (_this) {
  if (typeof this !== "function") {
    throw new TypeError("_this must be a function");
  }
  //获取参数
  let args0 = [...arguments].slice(1);
  //保存this,如果作为构造函数使用,此时this会指向实例
  let that = this;
  let context = _this||window;
  return function Fn(...args) {
    // 如果是new的形式来使用绑定函数的
    if (this instanceof Fn) {
      return new that(...args0, ...args);
    } else {
      return that.call(context , ...args0, ...args);
    }
  };
};

//测试:
function Point(x, y) {
  this.x = x;
  this.y = y;
}

// 情况1:正常调用bind函数
let testObj = {};
let MyPoint = Point.myBind(testObj, 0);
MyPoint(1);
console.log(testObj);
//情况2:bind返回的函数作为构造函数
let newObj = new MyPoint(2);
console.log(newObj);

结果:

四、区别:

1、相同点:

(1) call、apply、bind 都有改变this指向的作用。

(2)都可以给参数传参

2、不同点:

(1)call、bind 的第二个、后续参数是多个;而apply接收的第二参数是数组。

(2)call、apply会立即执行参数;而bind不会立即执行,得再调用才能执行。

参考:

1、https://blog.csdn.net/weixin_51472145/article/details/132566180

2、https://blog.csdn.net/weixin_40856652/article/details/124293144?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171348813116800178533534%2522%252C%2522scm%2522%253A%252220140713.130102334...%2522%257D&request_id=171348813116800178533534&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-124293144-null-null.142^v100^pc_search_result_base1&utm_term=call%E3%80%81apply%E5%92%8Cbind%E7%9A%84%E5%8C%BA%E5%88%AB&spm=1018.2226.3001.4187

3、https://blog.csdn.net/sinat_41904410/article/details/104396112

相关推荐
上海_彭彭19 分钟前
【提效工具开发】Python功能模块执行和 SQL 执行 需求整理
开发语言·python·sql·测试工具·element
3345543228 分钟前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test29 分钟前
js下载excel示例demo
前端·javascript·excel
沈询-阿里32 分钟前
java-智能识别车牌号_基于spring ai和开源国产大模型_qwen vl
java·开发语言
PleaSure乐事44 分钟前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
残月只会敲键盘1 小时前
面相小白的php反序列化漏洞原理剖析
开发语言·php
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
ac-er88881 小时前
PHP弱类型安全问题
开发语言·安全·php
ac-er88881 小时前
PHP网络爬虫常见的反爬策略
开发语言·爬虫·php
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript