实现call()、apply()、bind()函数及各自使用场景

本文主要讲解实现call()、apply()、bind()函数及使用场景举例。在JavaScript中,call()apply(), 和 bind() 是函数对象的方法,它们允许你以不同的方式调用函数,并可以设置函数体内 this 的值。this相关与这三个函数介绍:文章第二部分

1. 实现 call()

实现 call() 方法时,需要创建一个新的函数上下文(通常是通过创建一个新的函数并立即执行它),以便在该上下文中调用原始函数,并将 this 指向设置为提供的参数。

实现步骤:

(1)判断调用对象是否为函数

(2)判断传入上下文对象是否存在。如果存入的参数为null或undefined,则使用全局对象(在浏览器中为window)

(3)将调用函数(this)赋值给参数的某个属性

(4)调用参数的新函数,并传入参数

(5)清理环境,删除在参数上临时创建的属性

(6)返回结果

示例:

// 实现call函数
Function.prototype.myCall = function(context, ...args) { // 判断函数是否存在if (typeof this!== 'function') {throw new TypeError('Error');}// 如果context为null或undefined,则使用全局对象(在浏览器中为window) context = context || window; // 将调用函数(this)赋值给context的某个属性context.fn=this;// 调用context上的新函数,并传入参数 const result = context.fn(...args); // 清理环境,删除在context上临时创建的属性 delete context.fn;// 返回结果return result; 
}; 
// 示例
function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation); 
} 
const personOne = { name: 'Alice' 
}; 
greet.myCall(personOne, 'Hello', '!'); // 输出: Hello, Alice! 
// 注意:在非严格模式下,如果context为null或undefined,this将指向全局对象(在浏览器中为window) 
greet.myCall(null, 'Hello', '!'); // 输出: Hello, undefined!(如果全局对象中没有name属性) 
// 在严格模式下,如果context为null或undefined,则this保持为null或undefined 

2. 实现 apply()

apply() 方法调用一个函数,其具有一个指定的 this 值,以及作为一个数组(或类数组对象)提供的参数。

实现步骤:

(1)判断调用对象是否为函数

(2)判断传入上下文对象是否存在。如果存入的参数为null或undefined,则使用全局对象(在浏览器中为window)

(3)将调用函数(this)赋值给参数的某个属性

(4)调用参数的新函数,并传入参数

(5)清理环境,删除在参数上临时创建的属性

(6)返回结果

示例:

// 实现apply函数
Function.prototype.myApply = function(context) { // 判断函数是否存在if (typeof this!== 'function') {throw new TypeError('Error');}// 如果context为null或undefined,则使用全局对象(在浏览器中为window) context = context || window; // 将调用函数(this)赋值给context的某个属性context.fn=this;// 调用context上的新函数,并传入参数 let result;if(arguments[1]){result = context.fn(...arguments[1]);}else{result = context.fn();}// 清理环境,删除在context上临时创建的属性 delete context.fn;// 返回结果return result; 
}; 
// 示例
function sum(a, b, c) {  return a + b + c;  
}  
console.log(sum.myApply(null, [1, 2, 3])); // 输出: 6 

注意:call()方法接收一个this参数和一系列单独的参数。apply()方法接收一个this参数和一个包含所有参数的数组或类数组对象。

3. 实现 bind()

实现bind函数主要是创建一个新的函数,这个新函数在被调用时,this值会被预设为bind的第一个参数,其余参数将作为新函数的参数,供调用时使用。

实现步骤:

(1)检查调用对象是否为函数

(2)创建并返回一个新函数

(3)处理新函数被用作构造函数的情况

(4)处理普通函数调用

(5)在新函数内部使用applycall调用原始函数

(6)返回新函数

示例:

// 实现bind函数
Function.prototype.myBind = function(context,...args) { // 判断函数是否存在if (typeof this!== 'function') {throw new TypeError('Error');}// 创建一个新函数const fn = (...innerArgs) => {// 如果新函数被作为构造函数使用,则this指向新创建的对象if (this instanceof fn) {return new this(...innerArgs,...args);}// 否则,this指向contextreturn this.apply(context, [...innerArgs,...args]);};// 复制原函数的prototypefn.prototype = Object.create(this.prototype);// 返回新函数return fn;
};
// 示例
const personTwo = {name: 'Bob'
};
const lizi = greet.myBind(personTwo, 'Hello');
lizi('!'); // !, BobHello

4.call()|apply()|bind()使用场景

call、‌apply和bind方法在JavaScript中主要用于改变函数执行时的上下文环境(即改变函数内部this的指向)。‌但是还有一些其他用处, 以下是这些方法的使用场景:‌

改变函数执行时的上下文环境:‌当函数被作为对象的方法调用时,‌this指向调用该方法的对象。‌需要控制函数内部的this指向其他对象,可以使用call、‌applybind方法来达到目的。‌

function greet() {  console.log('Hello, ' + this.name + '!');  
}  const person = {  name: 'Alice'  
};  // 使用call  
greet.call(person); // 输出: Hello, Alice!  // 使用apply(与call类似,但第二个参数是数组)  
greet.apply(person); // 输出: Hello, Alice!  

实现继承:‌可以使用这些方法来实现继承。‌例通过call方法调用父构造函数来实现子类继承父类的属性和方法。‌

function Parent(name) {  this.name = name;  this.sayHello = function() {  console.log('Hello, ' + this.name);  };  
}  function Child(name, age) {  Parent.call(this, name); // 继承Parent的name属性  this.age = age;  
}  const child = new Child('Bob', 10);  
child.sayHello(); // 输出: Hello, Bob  

与事件处理相关:‌在处理DOM事件时,‌经常需要改变事件处理函数的上下文环境,‌以便正确地访问事件对象或其他相关数据。‌可以使用bind方法来创建一个新的函数。‌

const button = document.getElementById('myButton');  function showMessage() {  console.log('Button clicked by ' + this.name);  
}  const person = {  name: 'Alice'  
};  // 使用bind将showMessage的this绑定到person对象  
button.addEventListener('click', showMessage.bind(person));  

与回调函数相关:‌如果需要在回调函数内部访问外部作用域的变量或对象,‌并希望回调函数内部的this指向特定的对象,‌可以使用bind方法来实现。‌

function fetchData(callback) {  // 假设这是从服务器获取的数据  const data = 'Some data';  // 调用回调函数,但确保回调函数内部的this指向正确的对象   const boundCallback = callback.bind(this);  boundCallback(data);  
}  const obj = {  name: 'Alice',  processData: function(data) {  console.log('Processing data for ' + this.name);  console.log(data);  }  
};  fetchData(obj.processData.bind(obj));

与异步编程相关:‌在异步编程中,‌如使用Promise或async/await时,‌可能需要控制回调函数的上下文环境。‌可以使用bind方法来确保回调函数内部的this指向正确的上下文。‌

function fetchUser(userId, callback) {  setTimeout(() => {  // 假设是从服务器获取的用户信息  const user = { id: userId, name: 'Alice' };  // 确保回调函数内部的this指向正确  // callback.bind(this)(user); const boundCallback = callback.bind(this);  boundCallback(user);  }, 1000);  
}  const context = {  logUser: function(user) {  console.log('User:', user.name);  },  
};  // 更好的做法是将bind的结果作为参数传递  
fetchUser(1, context.logUser.bind(context));

注意:在异步编程中直接使用bind然后立即调用不是最佳实践。因为bind返回的是一个新函数,如果直接调用(如callback.bind(this)(user);),则不会按预期工作。

通常会将bind的结果赋值给一个变量,然后使用该变量来调用函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/877012.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频监控管理平台LntonAIServer智能视频监控平台在工业排污检测中的应用

随着工业化的不断发展,环境污染问题日益严重。为了保护生态环境,各国政府纷纷出台相关政策,对工业排污进行严格监管。然而,传统的排污检测方法往往耗时耗力,且难以实现实时监控。因此,如何提高工业排污检测…

Graph-RAG:知识图谱与大模型的融合

在数字化的浪潮中,知识的累积已非线性增长,以指数级的速度膨胀。我们站在一个信息过载的十字路口,迫切需要一种能力,能够穿透数据的迷雾,捕捉知识的精髓。本文将揭示 Graph-RAG 的神秘面纱,这是一种突破传统…

FBMM: Making Memory Management Extensible With Filesystems——论文泛读

ATC 2024 Paper 论文阅读笔记整理 问题 CXL这样的新内存技术实现了多种内存配置,如分层内存、远内存和内存处理。为了支持这些新的硬件配置,需要对操作系统进行大量修改。例如,Meta的TPP内核补丁对NUMA和页面回收策略进行了更改&#xff0c…

PMP证书含金量高吗?值得考吗?

值啊,我考过了,PMP 是项目管理岗位的敲门砖,很多企业都写明了持有PMP 证书的优先,而且学完这个知识体系,对我的能力提升确实有帮助,还是值得的。 一、为什么值得 这个证书就是基础知识,项目管…

系统架构设计师 - 知识产权与标准化

知识产权与标准化 知识产权与标准化(3分)保护范围与对象 ★ ★ ★ ★法律法规 保护期限 ★ ★知识产权人确定 ★ ★ ★ ★侵权判断 ★ ★ ★ ★标准化(了解)★标准的分类标准的编号 大家好呀!我是小笙,本章…

数据库实验:数据库安全性

一、实验目的: 1、掌握SQL SERVER的身份验证方式。 2、掌握SQL SERVER的权限。 3、掌握给数据库的用户和角色赋予权限和从用户和角色收回权限。 4、掌握GRANT,REVOKE,DENY的用法。 二、实验内容: 1、将SQL SERVER服务器的安全…

爬虫-通过几个例子来说明并发以及多线程

并发 什么是并发?并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。 嗯,字认识&#…

滞回比较器工作原理,应用,TINA仿真

滞回比较器 滞回比较器的主要应用是增加滞回控制,让其对微小的变化不那么敏感,增强抗干扰能力,避免由噪声引起的不稳定状态,通常用于噪声环境下的阈值检测以及信号调理。根据不同需求,滞回比较器还可以设计成开漏极输出…

Redis的使用场景——热点数据缓存

热点数据缓存 Redis的使用场景——热点数据的缓存 1.1 什么是缓存 为了把一些经常访问的数据,放入缓存中以减少对数据库的访问效率,从而减少数据库的压力,提高程序的性能。【在内存中存储】 1.2 缓存的原理 查询缓存中是否存在对应的数据如…

[240728] Wikidata 介绍 | 微软与 Lumen 合作提升人工智能算力

目录 Wikidata 介绍微软与 Lumen 合作提升人工智能算力 Wikidata 介绍 中文: 文言: 粤语: 来源: https://www.wikidata.org/wiki/Wikidata:Introduction/zh 微软与 Lumen 合作提升人工智能算力 为了满足人工智能工作负载不断增长的需求&am…

从零开始写 Docker(十九)---增加 cgroup v2 支持

本文为从零开始写 Docker 系列第十九篇,添加对 cgroup v2 的支持。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识: 核心原理:深入理解 Docker 核心原理&#xff1a…

微软蓝屏”事件暴露了网络安全哪些问题?

📢博客主页:https://blog.csdn.net/2301_779549673 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 JohnKi 原创,首发于 CSDN🙉 📢未来很长&#…

cadence SPB17.4 - allegro - 设置不同网络之间的距离规则

文章目录 cadence SPB17.4 - allegro - 设置不同网络之间的距离规则概述笔记END cadence SPB17.4 - allegro - 设置不同网络之间的距离规则 概述 插座进来的管脚,可能带来高压(有可能用户接错,或者出现浪涌,或者做ESD静电测试&a…

SpringBoot热部署重启关闭(DevTools)

一、DevTools依赖 1、DevTools简介 在Spring Boot项目中,spring-boot-devtools模块提供了多种开发时的便利功能,其中最显著的是restart和livereload特性,它们分别用于应用代码的热重启和前端资源的即时重载。 devtools依赖: &l…

如何在调整节拍时间的过程中保持生产流程的稳定性?

在快节奏的工业生产领域,节拍时间(Takt Time)——即完成一个完整产品所需的标准时间,是维持生产效率和流程稳定性的关键指标。然而,市场需求的波动、技术升级或是生产线的微调,都可能要求我们对节拍时间进行…

Redis-主从模式

目录 前言 一.主从节点介绍 二.配置redis主从结构 二.主从复制 四.拓扑结构 五.数据同步 全量复制(Full Sync Replication) 局部复制(Partial Replication) Redis的学习专栏:http://t.csdnimg.cn/a8cvV 前言 …

docker安装phpMyAdmin

直接安装phpMyAdmin需要有php环境,比较麻烦,总结了使用docker安装方法,并提供docker镜像。 1.docker镜像 见我上传的docker镜像:https://download.csdn.net/download/taotao_guiwang/89595177 2.安装 1).加载镜像 docker load …

AC/DC和DC/DC开关电源的传导和辐射原理

电磁干扰(EMI)始终是开关电源(AC/DC和DC/DC转换器)的潜在问题。如今的电源有很好的电磁发射和抗干扰的能力。但为了满足特定的应用要求,仍要有正确的滤波电路以确保满足标准的要求。 基于AC/DC和DC/DC电源模块的很佳EM…

CentOS7使用yum安装MySQL

废话不多说,直接上干货 1、CentOS7的yum源中默认是没有mysql的,我们先下载mysql的repo源 wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 2、安装mysql-community-release-el7-5.noarch.rpm包 sudo rpm -ivh mysql-community-r…

商城购物系统

下载在最后 技术栈: ssmmysqljsp 展示: 下载地址: CSDN现在上传有问题,有兴趣的朋友先收藏.正常了贴上下载地址 备注: