如何理解和使用 this 关键字

this 关键字是许多编程语言中的一个核心概念,在面向对象编程(OOP)中尤为重要。在JavaScript、Java、C++、C#等语言中,this 扮演着至关重要的角色。理解 this 的意义和用法,对于编写清晰、有效的代码至关重要。

什么是this

简单来说,this 关键字在面向对象编程中指代的是“当前对象”——即方法或函数被调用时所关联的对象。this 的具体值根据其上下文而变化,可以指代不同的对象。理解和正确使用 this 是编写灵活、重用代码的基础。

JavaScript中的this

全局上下文中的this

在全局上下文(即非严格模式下的全局代码)中,this 指向全局对象。对于浏览器中的JavaScript,全局对象是 window

console.log(this === window); // true

在严格模式下,全局上下文中的 thisundefined

"use strict";
console.log(this); // undefined
函数上下文中的this

在函数调用中,this 的值取决于函数的调用方式。

  • 普通函数调用: 在非严格模式下,this 依然指向全局对象。
function foo() {
  console.log(this);
}
foo(); // 在浏览器中,this 指向 window
  • 严格模式下的函数调用: thisundefined
"use strict";
function foo() {
  console.log(this);
}
foo(); // undefined
方法调用中的this

当方法作为对象的属性调用时,this 指向调用该方法的对象。

const obj = {
  name: 'Alice',
  greet: function() {
    console.log(this.name);
  }
};

obj.greet(); // 'Alice'
构造函数中的this

构造函数是一种特殊的函数,用于创建对象。使用 new 操作符调用构造函数时,this 指向新创建的对象。

function Person(name) {
  this.name = name;
}

const person1 = new Person('Alice');
console.log(person1.name); // 'Alice'
箭头函数中的this

箭头函数在定义时绑定 this,其值为定义时所在上下文的 this,而不是调用时的 this。这是与传统函数的一个显著区别。

const obj = {
  name: 'Alice',
  greet: function() {
    const inner = () => {
      console.log(this.name);
    };
    inner();
  }
};

obj.greet(); // 'Alice'

在上例中,箭头函数 innerthis 绑定在 greet 方法定义时的 this,即 obj

Java中的this

类的实例方法中的this

在Java中,this 关键字在实例方法中指代当前对象。

public class Person {
  private String name;

  public Person(String name) {
    this.name = name;
  }

  public void greet() {
    System.out.println("Hello, " + this.name);
  }

  public static void main(String[] args) {
    Person person = new Person("Alice");
    person.greet(); // Hello, Alice
  }
}

在上例中,this.name 访问的是当前对象的 name 属性。

构造器中的this

在构造器中,this 也指向当前对象。构造器可以调用类中的另一个构造器,这称为构造器链(constructor chaining)。

public class Person {
  private String name;
  private int age;

  public Person(String name) {
    this(name, 0); // 调用另一个构造器
  }

  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
}
匿名类中的this

在Java中,匿名类是没有名字的内部类。匿名类中的 this 关键字指向匿名类的实例,而不是包含匿名类的外部类的实例。

public class Outer {
  private String name = "Outer";

  public void createInner() {
    new Thread(new Runnable() {
      private String name = "Inner";
      public void run() {
        System.out.println(this.name); // Inner
      }
    }).start();
  }

  public static void main(String[] args) {
    Outer outer = new Outer();
    outer.createInner();
  }
}

C++中的this

在C++中,this 是一个指向当前对象的指针。

类的成员函数中的this

在成员函数中,this 指向当前对象。

class Person {
  std::string name;
public:
  Person(std::string name) : name(name) {}

  void greet() {
    std::cout << "Hello, " << this->name << std::endl;
  }
};

int main() {
  Person person("Alice");
  person.greet(); // Hello, Alice
}
链式调用

C++中的 this 指针可以用于返回对象本身,以支持链式调用(method chaining)。

class Person {
  std::string name;
public:
  Person& setName(const std::string& name) {
    this->name = name;
    return *this;
  }

  void greet() const {
    std::cout << "Hello, " << this->name << std::endl;
  }
};

int main() {
  Person person("Alice");
  person.setName("Bob").greet(); // Hello, Bob
}

C#中的this

在C#中,this 关键字用于引用当前实例。

实例方法中的this

在实例方法中,this 指向当前对象。

public class Person {
  private string name;

  public Person(string name) {
    this.name = name;
  }

  public void Greet() {
    Console.WriteLine("Hello, " + this.name);
  }

  public static void Main(string[] args) {
    Person person = new Person("Alice");
    person.Greet(); // Hello, Alice
  }
}
构造函数中的this

C#中,构造函数可以通过 this 关键字调用另一个构造函数。

public class Person {
  private string name;
  private int age;

  public Person(string name) : this(name, 0) { }

  public Person(string name, int age) {
    this.name = name;
    this.age = age;
  }
}
扩展方法中的this

在C#中,扩展方法允许我们向现有类型添加方法,而无需创建新的派生类型。扩展方法的第一个参数是 this,表示被扩展的类型实例。

public static class PersonExtensions {
  public static void Introduce(this Person person) {
    Console.WriteLine("My name is " + person.Name);
  }
}

public class Person {
  public string Name { get; set; }
}

public class Program {
  public static void Main() {
    Person person = new Person { Name = "Alice" };
    person.Introduce(); // My name is Alice
  }
}

this 关键字的实际应用

避免命名冲突

在构造函数和方法中,this 常用于避免命名冲突。例如,当参数名称与成员变量名称相同时,可以使用 this 区分二者。

public class Person {
  private String name;

  public Person(String name) {
    this.name = name; // 使用 this 区分成员变量和参数
  }
}
方法链(Method Chaining)

通过返回 this,我们可以在同一对象上连续调用多个方法,实现方法链。

class Person {
  constructor(name) {
    this.name = name;
  }

  setName(name) {
    this.name = name;
    return this;
  }

  greet() {
    console.log("Hello, " + this.name);
    return this;
  }
}

const person = new Person('Alice');
person.setName('Bob').greet(); // Hello, Bob
事件处理程序中的this

在JavaScript中,事件处理程序常使用 this 访问触发事件的元素。

<button id="btn">Click me</button>

<script>
  document.getElementById('btn').addEventListener('click', function() {
    console.log(this.id); // btn
  });
</script>
this 在回调函数中的使用

在回调函数中,this 的值可能不如预期。这种情况下,可以使用 .bind() 方法明确绑定 this,或者使用箭头函数。

const obj = {
  name: 'Alice',
  greet: function() {
    setTimeout(function() {
      console.log(this.name); // undefined,因为 this 指向全局对象
    }.bind(this), 1000);
  }
};

obj.greet(); // Alice

或使用箭头函数:

const obj = {
  name: 'Alice',
  greet: function() {
    setTimeout(() => {
      console.log(this.name); // Alice,因为箭头函数不会绑定自己的 this
    }, 1000);
  }
};

obj.greet(); // Alice

this 关键字在不同的编程语言中具有类似的概念,但其具体行为和使用场景可能有所不同。在JavaScript中,this 的值取决于函数的调用方式,使用不当可能导致意外结果。而在Java、C++、C#等语言中,this 通常更为直观,指代当前实例。

理解 this 的关键在于清楚其在不同上下文中的指代对象,通过实际应用和实践,可以更好地掌握和利用这一重要概念,提高代码的可读性和可维护性。

黑马程序员免费预约咨询

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OrangePi Kunpeng Pro体验——安装Hass与驱动SPI小屏幕

OrangePi Kunpeng Pro 是一款面向开发者和爱好者的高性能开发板。在本次测评中&#xff0c;主要将以前的一些代码在该开发板上实现&#xff0c;包括docker部署hass&#xff0c;引脚驱动SPI小屏幕。中间遇到了一些小小问题&#xff0c;但都成功了&#xff0c;一起来试试吧~ 一、…

wifi贴码推广哪家靠谱?

如今越来越多的人想轻资产创业&#xff0c;WIFI贴码是共享行业最无成本的创业项目了&#xff0c;而在选择厂商的时候&#xff0c;大家就想要知道哪家公司靠谱&#xff0c;更好、更便宜、可靠。那么wifi贴码推广哪家靠谱&#xff1f;别急&#xff0c;下面小编将带你一起了解。 目…

LLM - 模型下载与 git-lfs 安装

目录 一.引言 二.安装 git lfs 1.使用 apt-get 安装 2.使用 Brew 安装 3.LFS 验证 三.总结 一.引言 在 HuggingFace 上下载模型时提供一个 git clone 的指令&#xff0c;执行后可以下载对应模型的模型文件: 但是本机还没有 git lfs 命令: git: lfs is not a git comman…

CPU对代码执行效率的优化,CPU的缓存、指令重排序

目录 一、CPU对代码执行效率的优化 1. 指令流水线&#xff08;Instruction Pipelining&#xff09; 2. 超标量架构&#xff08;Superscalar Architecture&#xff09; 3. 动态指令重排序&#xff08;Dynamic Instruction Reordering&#xff09; 4. 分支预测&#xff08;…

文献解读-群体基因组第二期|《中国人群中PAX2新生突变的检测及表型分析:一项单中心研究》

关键词&#xff1a;应用遗传流行病学&#xff1b;群体测序&#xff1b;群体基因组&#xff1b;基因组变异检测&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;Detection of De Novo PAX2 Variants and Phenotypes in Chinese Population: A Single-Cente…

下一代 CI/CD:利用 Tekton 和 ArgoCD 实现云原生自动化

一、回顾目标 背景&#xff1a; ​ 部门业务上云&#xff0c;之前服务采用传统的部署方式&#xff0c;这种方式简单&#xff0c;但是不能为应用程序定义资源使用边界&#xff0c;很难合理地分配计算资源&#xff0c;而且程序之间容易产生影响。随着互联网时代的到来&#xff…

【Chrono Engine学习总结】6-创建自定义场景-6.1-3D场景获取

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 Chrono可以导入自定义的三维模型&#xff0c;所以想自己搭建一个3D仿真环境。过程中遇到了一些问题&#xff0c;记录与整理。 1、3D环境的创建方法 Chrono的Irrlich…

2024年6月1日(星期六)骑行禹都甸

2024年6月1日 (星期六&#xff09;骑行禹都甸&#xff08;韭葱花&#xff09;&#xff0c;早8:30到9:00&#xff0c;昆明氧气厂门口集合&#xff0c;9:30准时出发【因迟到者&#xff0c;骑行速度快者&#xff0c;可自行追赶偶遇。】 偶遇地点:昆明氧气厂门口集合 &#xff0c;…

视频监控业务平台LntonCVS运用国标协议对接视频汇聚管理综合平台应用方案

为了实现“以信息化推动应急管理能力现代化”的目标&#xff0c;应急管理部提出了加速现代信息技术与应急管理业务深度融合的计划。这一计划是国家加强和改进应急管理工作的关键举措&#xff0c;也是满足日益严峻的应急管理形势和人民群众不断增长的公共安全需求的紧迫需求。 为…

12个好用的视频自动加字幕工具

多个提供视频字幕生成及翻译服务的工具和平台&#xff0c;涵盖了从自动识别到翻译、配音等多种功能&#xff0c;适合不同需求的用户选择使用。 网易见外: 支持视频智能字幕功能&#xff0c;转换正确率高&#xff0c;转换后的字幕可以直接导入Pr和会声会影等主流剪辑工具&#…

【Axure教程】拖动换位选择器

拖动换位选择器通常用于从一个列表中选择项目并将其移动到另一个列表中。用户可以通过拖动选项来实现选择和移动。这种交互方式在许多Web应用程序中很常见&#xff0c;特别是在需要对项目分组的情况下。 所以今天作者就教大家怎么在Axure用中继器制作一个拖动换位选择器的原型…

【Linux】初识Linux和Linux环境配置

1.什么是Linux操作系统 说到电脑系统 我想有大多数人会脱口而出&#xff1a;windows、mac 是的&#xff0c;这也是如今市场上主流的两种操作系统。 但是对于IT相关的人士来说&#xff0c;还有一种系统也是必须有姓名 那就是Linux Linux&#xff0c;Linux Is Not UniX 的…

Java_认识String类

在 C 语言中已经涉及到字符串了&#xff0c;但是在 C 语言中要表示字符串只能使用字符数组或者字符指针&#xff0c; 可以使用标准库提 供的字符串系列函数完成大部分操作&#xff0c;但是这种将数据和操作数据方法分离开 的方式不符合面相对象的思想&#xff0c;而字符串应用又…

VI 使用替换命令快速注释多行

使用替换命令快速注释多行&#xff1a; 按下 Esc 键确保你在普通模式下。输入 :起始行号,结束行号s/^/#/ 并按 Enter 键。 :起始行号 和 结束行号 分别是你要注释的起始行和结束行的行号。 关于正则 s/^/#/各个部分解释&#xff1a; s/: 这是vi编辑器中的替换命令的开头。s 表…

【Linux】centos7编写C语言程序,补充:使用yum安装软件包组

确保已安装gcc编译器 C语言程序&#xff0c;一般使用gcc进行编译&#xff0c;需确保已安装gcc。 若没有&#xff0c;可以使用yum安装gcc&#xff08;版本4.8.5&#xff09;&#xff0c;也可以使用SCL源安装gcc&#xff08;例如&#xff1a;版本9.3&#xff09;。 安装gcc&am…

htb_BoardLight

信息收集 nmap -sSVC 10.10.11.11开放80端口&#xff0c;将boardlight.htb写入/etc/hosts 同步进行子域名和目录扫描 子域名扫不到 这个目录扫描很奇怪哈&#xff0c;明明访问80端口有页面&#xff0c;就是扫不出来 直接浏览器访问80端口&#xff0c;四处看看&#xff0c;发…

Blazor入门-连接MySQL的简单例子:列出数据+简单查询

参考&#xff1a; ASP.NET Core 6.0 Blazor Server APP并使用MySQL数据库_blazor mysql-CSDN博客 https://blog.csdn.net/mzl87/article/details/129199352 本地环境&#xff1a;win10, visual studio 2022 community, mysql 8.0.33 (MySQL Community Server), net core 6.0 目…

DiffIR论文阅读笔记

ICCV2023的一篇用diffusion模型做Image Restoration的论文&#xff0c;一作是清华的教授&#xff0c;还在NIPS2023上一作发表了Hierarchical Integration Diffusion Model for Realistic Image Deblurring&#xff0c;作者里甚至有Luc Van Gool大佬。模型分三个部分&#xff0c…

Linux静态库、共享动态库介绍、制作及使用

参考学习&#xff1a;Linux下的各种文件 、动态库基本原理和使用方法&#xff0c;-fPIC选项的来龙去脉 、Linux静态库和动态库分析 文章写作参考&#xff1a;Linux共享库、静态库、动态库详解 - sunsky303 - 博客园 (cnblogs.com) 一.Linux共享库、静态库、动态库详解 使用G…

三十五岁零基础转行成为AI大模型开发者怎么样呢?

以下从3个方面帮大家分析&#xff1a; 35岁转行会不会太晚&#xff1f;零基础学习AI大模型开发能不能学会&#xff1f;AI大模型开发行业前景如何&#xff0c;学完后能不能找到好工作&#xff1f; 一、35岁转行会不会太晚&#xff1f; 35岁正处于人生的黄金时期&#xff0c;拥…