【Javascript】如何使用 this 关键字,call()、bind()、apply() 方法

news2024/9/30 5:40:27

学习 call(), apply(), 和 bind() 方法是很重要的,因为它们让你能够控制 JavaScript 中 this 的上下文。在某些情况下,默认的 this 行为可能不符合预期,比如当你从一个对象借用方法到另一个对象,或者是在回调函数中保持正确的上下文时,这些方法提供了灵活性和控制力。通过掌握它们,你可以编写出更加高效、可复用并且上下文感知的函数,这在复杂的应用中尤其有用。

在我们深入了解 call(), apply(), 和 bind() 方法之前,先来了解一下 'this' 关键字及其工作机制。

'this' 关键字

让我们通过下面的要点来理解什么时候以及 this 关键字指的是什么:

  • 在一个对象的方法中, this 指向该对象。在对象内部定义的方法中,this 将指向拥有该方法的对象。

  • 在一个普通函数中, this 指向全局对象。在非严格模式下,如果函数是在全局上下文中调用(而不是作为对象的方法),this 指向的是全局对象(在浏览器中是 window)。

  • 在严格模式下的函数中, thisundefined。如果函数不是某个对象的方法,并且没有绑定到特定上下文(通过 call, apply, 或 bind),那么在严格模式下 this 将是 undefined

  • 在事件处理程序中, this 指向接收事件的元素。当触发事件时,this 指向的是触发事件的 HTML 元素。

    <button onclick="this.style.display='none'">
      点击移除我!
    </button>
    

    在这里,this 指向的是接收到 onclick 事件的按钮元素本身。

在箭头函数中, this 的行为有所不同。箭头函数没有自己的 this 上下文。相反,this 以词法形式继承自创建箭头函数时周围的上下文。这意味着箭头函数内部的 this 指向的是其外部函数或上下文的 this 值。

const person = {
  name: "Alice",
  greet: function() {
    setTimeout(() => {
      console.log(`嗨,我是 ${this.name}`);
    }, 1000);
  }
};

person.greet(); // 输出: 嗨,我是 Alice

在这个例子中,setTimeout 内部的箭头函数继承了 greet 方法的 this,后者指向 person 对象。

call() 方法

call() 方法允许你“借用”一个对象上的函数或方法,并用另一个对象来使用它,只需把另一个对象作为第一个参数传递即可。第一个参数成为了函数内部的 this 值,而其他参数紧随其后。

call() 方法并不会创建新的函数;它只是用提供的上下文和参数运行现有的函数。

const person = {
  fullName: function(city, country) {
    console.log(this.firstName + " " + this.lastName + " 正准备去 " + city + ", " + country + ".");
  }
}

const person1 = {
  firstName: "John",
  lastName: "Doe"
}

person.fullName.call(person1, "Oslo", "Norway");
// 输出: John Doe 正准备去 Oslo, Norway.

在这个例子中,call() 被用来执行 person 对象中的 fullName 方法,但是使用了 person1 的数据(firstNamelastName),附加的参数则是 “Oslo” 和 “Norway”。

apply() 方法

apply() 方法和 call() 方法非常相似。主要区别在于参数是如何传递给函数的。使用 apply() 时,你可以将参数作为一个数组(或类数组对象)传递,而不是单独传递。

call() 一样,apply() 方法也不会创建新的函数。它立即执行函数,使用提供的上下文 (this 值) 和参数。

const person = {
  fullName: function(city, country) {
    console.log(this.firstName + " " + this.lastName + " 正准备去 " + city + ", " + country + ".");
  }
}

const person1 = {
  firstName: "John",
  lastName: "Doe"
}

person.fullName.apply(person1, ["Oslo", "Norway"]);
// 输出: John Doe 正准备去 Oslo, Norway.

在这个例子中,apply() 被用来调用 person 对象中的 fullName 方法,但是上下文 (this) 设置为了 person1。参数 “Oslo” 和 “Norway” 作为一个数组传递。

bind() 方法

JavaScript 中的 bind() 方法让你能够设置一个函数或方法的上下文(this 值),就像 call()apply() 一样。然而,不同于 call()apply()bind() 方法不会立即调用函数。相反,它返回一个新的函数,其中 this 值被设置为你指定的对象。

const person = {
  fullName: function(city, country) {
    console.log(this.firstName + " " + this.lastName + " 正准备去 " + city + ", " + country + ".");
  }
}

const person1 = {
  firstName: "John",
  lastName: "Doe"
}

const func = person.fullName.bind(person1);
func("Oslo", "Norway");
// 输出: John Doe 正准备去 Oslo, Norway.

在这个例子中,bind() 创建了一个新的函数 func,其中 this 值被设置为 person1。这个函数不会立即被调用,但你可以稍后传入参数 “Oslo” 和 “Norway” 来调用它。

示例:带有多上下文的集中式记录器

这里有一个小型但复杂的应用示例,在这个例子中使用 call(), apply(), 或 bind() 可以提高效率——尤其是在处理用于记录目的的函数的部分应用时:

假设你有一个集中式的记录函数,用于记录不同用户执行的动作。使用 bind() 可以有效地将 this 上下文设置为不同的用户,避免了重复代码。

const logger = {
  logAction: function(action) {
    console.log(`${this.name} (ID: ${this.id}) 执行了: ${action}`);
  }
};

const user1 = { name: "Alice", id: 101 };
const user2 = { name: "Bob", id: 202 };

// 为不同的用户创建新的记录函数
const logForUser1 = logger.logAction.bind(user1);
const logForUser2 = logger.logAction.bind(user2);

// 执行动作时无需手动传递用户上下文
logForUser1("login");
// 输出: Alice (ID: 101) 执行了: login

logForUser2("purchase");
// 输出: Bob (ID: 202) 执行了: purchase

为什么这样更高效?

上下文重用: 每次记录动作时,你都不需要手动传递用户上下文。上下文 (this) 只绑定一次,使记录变得可重用且干净。

模块化: 如果你需要添加更多用户或动作,你可以快速地将它们绑定到 logger 上,而不必改变函数本身,使你的代码保持 DRY(不要做重复的工作)。

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

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

相关文章

http请求过程 part-2

http请求过程 http应用层 实体 实体分为实体首部和实体主体&#xff0c;实体首部是用来描述主体的 实体部分是可选的&#xff0c;它被用来运送请求或者响应的数据 传输层-TCP HTTP连接是建立在TCP连接的基础上 以流形式通过一条已经打开的TCP连接&#xff0c;按顺序进行…

Django Web开发接口定义

Django Web 介绍 Django Web是一个Pyhton高级 Web 框架,实际上 Django 也可以做到前后端分离,即主要作为后端框架使用,不用模板渲染也是可行的。 Django Web 应用的运行流程,如下图所示: 此外,Django Web 在开发环境可以通过自带的服务器进行本地调试。但是该服务器不适…

LeetCode从入门到超凡(五)深入浅出---位运算

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年9月学习赛的LeetCode学习总结文档&#xff1b;本文主要讲解 位运算算法。&#x1f495;&#x1f495;&#x1f60a; 一、 位运算简介 1.什么是位…

【腾讯元宝-免费论文精读】

【腾讯元宝-免费论文精读】 1. 腾讯混元大模型2. 论文精读过程3. 总结&#xff1a; 1. 腾讯混元大模型 由腾讯研发的大语言模型&#xff0c;具备强大的中文创作能力&#xff0c; 复杂语境下的逻辑推理能力&#xff0c;以及可靠的任务执行能力 腾讯元宝&#xff1a;轻松工作&am…

Django对接支付宝沙箱环境(2024年9月新测有效)

1、申请沙箱环境 #需要填一些个人信息 https://opendocs.alipay.com/ 2、使用支付宝登入&#xff0c;并进入控制台&#xff0c;进入开发者工具推荐-->沙箱 3、获取基本信息 主要是APPID,和支付宝网关地址 4、生成应用私钥和应用公钥和支付宝公钥 上面的接口加签方式选择…

【Linux 22】生产者消费者模型

文章目录 &#x1f308; 一、生产者消费者模型⭐ 1. 生产者消费者模型的概念⭐ 2. 生产者消费者模型的特点⭐ 3. 生产者消费者模型的优点 &#x1f308; 二、基于阻塞队列的生产消费模型⭐ 1. 阻塞队列概念⭐ 2. 模拟实现基于阻塞队列的生产消费模型 &#x1f308; 三、POSIX 信…

Kubernetes云原生存储解决方案之 Rook Ceph实践探究

Kubernetes云原生存储解决方案之 Rook Ceph实践探究 除了手动部署独立的 Ceph 集群并配置与Kubernetes进行对接外&#xff0c;Rook Ceph 支持直接在 Kubernetes 集群上部署 Ceph 集群。 通过Rook Ceph云原生存储编排平台&#xff0c;使得 Kubernetes 集群中启用高可用的 Ceph…

PHP 基础语法详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【有啥问啥】多目标跟踪SORT算法原理详解

多目标跟踪SORT算法原理详解 引言 多目标跟踪&#xff08;Multiple Object Tracking, MOT&#xff09;是计算机视觉领域的一个重要研究方向&#xff0c;广泛应用于视频监控、自动驾驶、人机交互等多个领域。其核心任务是在视频序列中持续、准确地识别和定位多个目标。SORT&am…

爬虫入门之爬虫原理以及请求响应

爬虫入门之爬虫原理以及请求响应 爬虫需要用到的库, 叫requests. 在导入requests库之前, 需要安装它, 打开cmd: 输入pip install 库名 pip install requests后面出现successful或requirement already就说明已经下载成功了!!! 下载出现的问题: 1.有报错或者是下载慢 修改镜像…

计算机的错误计算(一百零八)

摘要 回复网友来信&#xff0c;接前一节本节再谈多项式的错误计算。 例1. 计算 若在Visual Studio 2010中用C#编程计算&#xff1a; using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(){ long part1 946495 * (…

Redis缓存双写一致性笔记(下)

Redis和Canal结合使用是一种常见的解决方案&#xff0c;用于确保MySQL数据库中的更改实时同步到Redis缓存中&#xff0c;从而保持数据的一致性。 这种同步机制虽然能够实现近乎实时的数据同步&#xff0c;但可能会有轻微的延迟&#xff0c;因此它更适合对数据一致性要求不是特…

STM32 DMA+AD多通道

单片机学习&#xff01; 目录 一、DMA配置步骤 二、ADC配置步骤 三、DMAAD多通道框图 四、DMAAD多通道函数设计详细步骤 4.1 开启RCC时钟 4.2 配置GPIO 4.3 配置多路开关 4.4 结构体初始化ADC 4.5 DMA参数初始化配置 4.5.1 外设站点的三个参数 4.5.2 存储器站点的三个…

Tomcat 调优技巧(Tomcat Tuning Tips)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

IDEA关联Tomcat

一、Tomcat服务器 web服务器,就是运行web项目的容器 即运行java代码的一个容器 webapp(web应用程序) --> 就是我们写的javaweb项目 Tomcat 是Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;下的一个核心项目&#xff0c;免费开源、并支持Servlet 和J…

yolov8/9/10模型在垃圾分类检测中的应用【代码+数据集+python环境+GUI系统】

yolov8/9/10模型在垃圾分类检测中的应用【代码数据集python环境GUI系统】 yolov8/9/10模型在垃圾分类检测中的应用【代码数据集python环境GUI系统】 背景意义 随着计算机视觉技术和深度学习算法的快速发展&#xff0c;图像识别、对象检测、图像分割等技术在各个领域得到了广泛…

DL_语义分割(学习笔记)

文章目录 图像分割1 常见分类1.1 语义分割1.2 实例分割1.3 全景分割 2 语义分割2.1 模型评价指标2.2 常用数据集2.3 转置卷积2.4 膨胀卷积2.5 感受野2.6 双线性插值2.7 FCN 图像分割 1 常见分类 1.1 语义分割 定义&#xff1a;【只判断类别&#xff0c;无法区分个体】 语义分…

Matlab实现麻雀优化算法优化回声状态网络模型 (SSA-ESN)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1内容介绍 麻雀搜索算法&#xff08;Sparrow Search Algorithm, SSA&#xff09;是一种新兴的群体智能优化算法&#xff0c;灵感来源于麻雀的觅食行为及其在面临危险时的预警机制。SSA通过模拟麻雀的这些自然行为来寻找问题…

[Docker学习笔记]利用Dockerfile创建镜像

Dockerfile 指令 指令作用from继承基础镜像maintainer镜像制作者信息(可缺省)run用来执行shell命令expose暴露端口号cmd启动容器默认执行的命令entrypoint启动容器真正执行的命令volume创建挂载点env配置环境变量add复制文件到容器copy复制文件到容器workdir设置容器的工作目录…

蓝卓亮相中国工博会,打造以数据驱动的智能工厂

9月28日&#xff0c;以“工业聚能&#xff0c;新质领航”为主题的第24届中国国际工业博览会&#xff08;以下简称“工博会”&#xff09;在国家会展中心&#xff08;上海&#xff09;圆满拉下帷幕。本届工博会共设9大专业展区&#xff0c;吸引了来自全球28个国家和地区的2600余…