call(), appy(),bind() 之间的区别与使用方法,自己实现这三个函数

call: 调用一个函数时,指定this,并分别传入参数

js 复制代码
Function.prototype.call(thisArg, arg1, arg2, /* ..., */ argN) 

演示代码:

js 复制代码
function sayName(...args) {
  console.log(this.name, ...args);
}

let person = {
  name: '张三',
};

sayName();

sayName.call(person, '参数1', '参数2');

自己实现call:

核心原理:把函数挂载 到要指向的对象上,执行这个函数,然后删掉这个临时属性

js 复制代码
Function.prototype.call2 = function (thisArg, ...args) {
  // 第一步:获取call绑定的对象
  let context = thisArg ?? globalThis;
  // 第二步:将被调用函数设置为对象的属性
  let fnName = Symbol('fn');
  context[fnName] = this;
  // 第三步:调用函数
  let result = context[fnName](...args);
  // 第四步:删除属性
  delete context[fnName];
  // 第五步:返回结果
  return result;
};

function sayName(...args) {
  console.log(this.name, ...args);
}

sayName();

let person = {
  name: '张三',
};

sayName.call2(person, '参数1', '参数2');

apply: 调用一个函数时,指定this,将参数封装为数组或者类数组传入

js 复制代码
Function.prototype.call(thisArg, argsArray) 

演示代码:

js 复制代码
function sayName(a, b) {
  console.log(this.name, a, b);
}

sayName('参数1', '参数2');

let person = {
  name: '张三',
};

sayName.apply(person, ['参数1', '参数2']);

自己实现apply:

核心原理:把函数挂载 到要指向的对象上,执行这个函数,然后删掉这个临时属性

globalThis:globalThis 是 JS 官方的 "全局对象,览器里 → globalThis === window,Node 里 → globalThis === global

js 复制代码
Function.prototype.apply2 = function (thisArg, argsArray) {
  // 第一步:获取apply绑定的对象
  let context = thisArg ?? globalThis;
  // 第二步:判断第二个参数不传的情况
  const args = argsArray ? [...argsArray] : [];
  // 第三步:将被调用函数设置为对象的属性
  let fnName = Symbol('fn');
  context[fnName] = this;
  // 第四步:调用函数
  let result = context[fnName](...args);
  // 第五步:删除属性
  delete context[fnName];
  // 第六步:返回结果
  return result;
};

function sayName(a, b) {
  console.log(this.name, a, b);
}

sayName('参数1', '参数2');

let person = {
  name: '张三',
};

sayName.apply2(person, ['参数1', '参数2']);

bind: 创建一个新函数,并指定该新函数运行时的this,并将指定的参数一一插入到原函数参数的前面

js 复制代码
let newFunc = Function.prototype.bind(thisArg,  arg1, arg2, /* ..., */ argN)

演示代码:

js 复制代码
function sayName(a, b, c, ...args) {
  console.log(this.name, a, b, c, ...args);
}

let person = {
  name: '张三',
};

let newSayName = sayName.bind(person, '参数1', '参数2', '参数3');

newSayName('参数4', '参数5', '参数6');

自己实现bind:

注意点:

  1. bind用于创建一个新函数,故应该返回一个函数,第一个参数是被绑定对象,后续参数用剩余参数接收

  2. bind返回的新函数若通过new关键字调用,则其this应该绑定到新创建的对象上而不是调用bind时指定的。所以需要通过new.target去判断函数的调用方式。

  3. 可以通过call()函数完成一部分bind函数的实现。

js 复制代码
Function.prototype.bind2 = function (thisArg, ...args) {
  // 第一步:获取bind绑定的对象
  let context = thisArg ?? globalThis;
  // 保存原函数
  let fn = this;

  return function (...newArgs) {
    // 如果函数是通过 new 调用的,this 应该指向新创建的对象,而不是 thisArg
    context = new.target ? this : context;
    // 调用原函数
    return fn.call(context, ...args, ...newArgs);
  };
};

function sayName(...args) {
  console.log(this === globalThis, this.name, ...args);
}

let person = {
  name: '张三',
};

let newSayName = sayName.bind2(person, '参数1', '参数2');

newSayName('参数3', '参数4'); // false 张三 参数1 参数2 参数3 参数4

new newSayName('参数5', '参数6'); // true undefined 参数1 参数2 参数5 参数6

new.target

ES6新增new.target,用于判断当前函数是被new构造调用还是被普通调用。

被new构造调用时,new.target的值是构造函数本身

被当作普通函数调用时,new.target的值是undefined

js 复制代码
function person(name, age) {
  this.name = name;
  this.age = age;
  console.log(new.target);
}

const p1 = new person('summer', 18); // [Function: person]

person('summer', 18); // undefined
相关推荐
码视野4 小时前
基于 Vue3 + Element Plus 的【无人值守共享自习室与空间智能预约系统】设计与实现(含PRD/三端源码/大屏)
前端·javascript·vue.js·人工智能·vue3
码视野4 小时前
基于 Vue3 + Element Plus 的【基于 Vue3 的智慧健身房会员管理与私教团课预约核销系统】设计与实现(附完整源码与PRD)
前端·vue3
烤羊腿的程序员4 小时前
前端面试知识点大全(带答案)
前端·面试·职场和发展
软件技术NINI5 小时前
传统文化html+css 5页
前端·css·html
优秀稳妥的JiaJi5 小时前
从产品原型到前端开发的需求清单,从1小时到25分钟
前端·trae
manongdashu1885 小时前
应对“SEO需要支付一年服务费”的捆绑消费,静态建站配套终身低成本服务器,全程无需额外运维开销。的方法。
运维·服务器·前端·seo·静态网站
风骏时光牛马5 小时前
AI提示词有效性深度测试
前端
Su米苏5 小时前
针对使用@vue-office 出现的包异常找不到问题
前端·javascript·vue.js
坚定信念,勇往无前5 小时前
electron打包mac ,apple m4出错:ffprobe是x86,不是arm64
前端·javascript·electron