this详解

对于刚开始进行 JavaScript 编程的开发者来说,this 具有强大的魔力,它像谜团一样需要工程师们花大量的精力去真正理解它。
在后端的一些编程语言中,例如 Java、PHP,this仅仅是类方法中当前对象的一个实例,它不能在方法外部被调用,这样一个简单的法则并不会造成任何疑惑。

在 JavaScript 中,this 是指当前函数中正在执行的上下文环境,因为这门语言拥有四种不同的函数调用类型:

  • 函数调用 alert(‘Hello World!’)
  • 方法调用 console.log(‘Hello World!’)
  • 构造函数调用 new RegExp(‘\d’)
  • 间接调用 alert.call(undefined, ‘Hello World’)

在以上每一项调用中,它都拥有各自独立的上下文环境,就会造成 this 所指意义有所差别。此外,严格模式也会对执行环境造成影响。
理解 this 关键字的关键在于理解各种不同的函数调用以及它是如何影响上下文环境的。

这篇文章旨在解释不同情况下的函数调用会怎样影响 this 以及判断上下文环境时会产生的一些常见陷阱。

在开始讲述之前,先熟悉以下一些术语:
调用 是执行当前函数主体的代码,即调用一个函数。例:parseInt 函数的调用为 parseInt(15)
上下文环境 是方法调用中 this 所代表的值
作用域 是一系列方法内可调用到的变量,对象,方法组成的集合

函数调用

函数调用 代表了该函数接收以成对的引号包含,用逗号分隔的不同参数组成的表达式。举例:parseInt(‘18’)。这个表达式不能是属性访问如 myObject.myFunction 这样会造成方法调用。[1, 5].join(‘,’) 同样也不是一个函数调用而是方法调用。

函数调用的一个简单例子:


hello(‘World’) 是一个函数调用:hello表达式代表了一个函数对象,接受了用成对引号包含的 World 参数。
高级一点的例子,立即执行函数 IIFE (immediately-invoked function expression):


函数调用中的 this

this is the global object in a function invocation
全局对象取决于当前执行环境,在浏览器中,全局对象即 window。
在函数调用中,上下文执行环境是全局对象,可以在以下函数中验证上下文:


当 sum(15, 16) 被调用时,JavaScript 自动将 this 设置为全局对象,即 window。
当 this 在任何函数作用域以外调用时(最外层作用域:全局执行上下文环境),也会涉及到全局对象



严格模式下,函数调用中的 this

this is undefined in a function invocation in strict mode
严格模式由 ECMAScript 5.1 引进,用来限制 JavaScript 的一些异常处理,提供更好的安全性和更强壮的错误检查机制。使用严格模式,只需要将 ‘use strict’ 置于函数体的顶部。这样就可以将上下文环境中的this 转为 undefined。
这样执行上下文环境不再是全局对象,与非严格模式刚好相反。
在严格模式下执行函数的一个例子:


当 multiply(2, 5) 执行时,这个函数中的 this 是 undefined。
严格模式不仅在当前作用域起到作用,它还会影响内部作用域,即内部声明的一切内部函数的作用域。



use strict 被插入函数执行主体的顶部,使严格模式可以控制到整个作用域。因为 concat 在执行作用域内部声明,因此它继承了严格模式。此外,concat(‘Hello’, ‘ World!’) 的调用中,this 也会成为undefined。
一个简单的 JavaScript 文件可能同时包含严格模式和非严格模式,所以在同一种类型调用中,可能也会有不同的上下文行为差异


陷阱:this 在内部函数中

一个常见的陷阱是理所应当的认为函数调用中的,内部函数中 this 等同于它的外部函数中的 this。
正确的理解是内部函数的上下文环境取决于调用环境,而不是外部函数的上下文环境。
为了获取到所期望的 this,应该利用间接调用修改内部函数的上下文环境,如使用 .call() 或者 .apply或者创建一个绑定函数 .bind()。
下面的例子表示计算两个数之和:


numbers.sum() 是对象内的一个方法调用,因此 sum 的上下文是 numbers 对象,而 calculate 函数定义在 sum 函数内,所以会误以为在 calculate 内 this 也指向的是 numbers。
然而 calculate() 在函数调用(而不是作为方法调用)时,此时的 this 指向的是全局对象 window 或者在严格模式下指向 undefined ,即使外部函数 sum 拥有 numbers对象作上下文环境,它也没有办法影响到内部的 this。
numbers.sum() 调用的结果是 NaN 或者在严格模式下直接抛出错误 TypeError: Cannot read property ‘numberA’ of undefined,而绝非期待的结果 5 10 = 15,造成这样的原因是 calculate 并没有正确的被调用。
为了解决这个问题,正确的方法是使 calculate 函数被调用时的上下文同 sum 调用时一样,为了得到属性numberA 和 numberB,其中一种办法是使用 .call() 方法。


calculate.call(this) 同样执行 calculate 函数,但是格外的添加了 this作为第一个参数,修改了上下文执行环境。此时的 this.numberA this.numberB 等同于 numbers.numberA numbers.numberB,其最终的结果就会如期盼的一样为 result 5 10 = 15。


<think>首先,用户的问题是:“我想理解Java中'this'关键字的用法和作用 请问Java this关键字详解及使用方法”。我需要基于系统级指令来回答。 系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 - 参考站内引用(用户提供了引用[1]到[5])。 用户提供的引用: - 引用[1]:解释了this关键字指代当前对象的引用,用于访问实例变量和方法,区分局部变量和成员变量。 - 引用[2]:讨论了this用于让类中的一个方法访问另一个方法或实例变量。 - 引用[3]:强调了在形参和成员变量重名时使用this来区分。 - 引用[4]:提到了this在构造方法中调用其他构造方法的用法。 - 引用[5]:关于synchronized关键字,与this无关,但我应该忽略不相关内容。 我的回答需要结构化: 1. 逐步解释this关键字的用法和作用。 2. 使用中文。 3. 在适当的地方添加引用标识。 4. 生成相关问题。 5. 确保LaTeX格式正确(虽然Java主题可能不涉及数学,但如果有数学表达式,需遵守规则;这里可能不适用)。 关键点从引用中提取: - this指代当前对象的引用。 - 用于访问实例变量和实例方法。 - 区分局部变量和成员变量。 - 在构造方法中调用其他构造方法(使用this())。 - 让一个方法访问另一个方法。 结构化的回答: 1. **介绍this关键字**:解释其基本概念和作用。 2. **主要用法**: - 区分成员变量和局部变量。 - 访问当前对象的成员。 - 在构造方法中调用其他构造方法。 3. **示例代码**:提供简单代码来演示用法。 4. **注意事项**:如不能在静态方法中使用this。 5. **生成相关问题**:在最后添加相关问题。 引用标识:在回答中,当引用特定内容时,添加[^1]等。用户提供的引用是参考,我需要自然地融入。 最终回答格式: - 开头:介绍问题。 - 主体:分点解释。 - 代码块:用于示例。 - 结尾:相关问题。 相关问题生成:基于主题,如: 1. this关键字在继承中的作用? 2. 如何在静态方法中处理类似需求? 3. this关键字的常见错误? 确保回答真实可靠:基于标准Java知识。</think>### Java中`this`关键字的详解及使用方法 在Java编程中,`this`关键字是一个重要的引用变量,它指代当前对象的引用。它只能在对象实例存在时使用(即在非静态方法中),主要用于访问当前对象的成员变量和成员方法。`this`的核心作用是解决变量名冲突、简化代码结构,并提高代码可读性。下面我将逐步解释其用法和作用,结合示例代码进行说明。参考引用中的关键点:`this`用于区分局部变量和成员变量[^1],在方法中访问另一个方法[^2],以及在构造方法中调用其他构造方法[^4]。 #### 1. `this`关键字的基本作用 - **指代当前对象**:`this`代表当前正在执行方法的对象实例。例如,在对象的方法内部,`this`可以访问该对象的成员变量和方法。 - **作用域限制**:`this`只能在非静态方法中使用,因为静态方法(如`main`方法)属于类级别,不依赖于具体对象实例[^1]。如果尝试在静态方法中使用`this`,编译器会报错。 #### 2. 主要用法详解 - **区分成员变量和局部变量**:当方法参数或局部变量与成员变量同名时,使用`this`可以明确指定访问成员变量,避免歧义。这是`this`最常见的用法。 - **示例代码**:以下代码中,构造方法`Person`的参数`name`和`address`与成员变量同名,`this.name`确保赋值给成员变量,而非局部变量。 ```java public class Person { private String name; // 成员变量 private String address; // 成员变量 public Person(String name, String address) { // 参数为局部变量 this.name = name; // 使用this区分:this.name指成员变量 this.address = address; // 不加this会导致局部变量覆盖成员变量 } public void display() { System.out.println("Name: " + this.name + ", Address: " + this.address); } } ``` 在`display`方法中,`this`是可选的,因为成员变量的作用域是整个实例,但加上`this`能增强可读性[^3]。 - **访问当前对象的成员方法**:`this`可用于调用当前对象的其他方法,避免创建不必要的对象实例。这在链式调用或方法间依赖时非常有用。 - **示例代码**:在`Dog`类中,`run`方法通过`this.jump()`调用`jump`方法,而不需要额外创建对象。 ```java public class Dog { public void jump() { System.out.println("执行jump方法"); } public void run() { this.jump(); // 使用this调用当前对象的jump方法 System.out.println("执行run方法"); } } ``` 如果不使用`this`,如引用[2]所示,可能需要创建新对象(如`Dog d = new Dog(); d.jump();`),这会增加内存开销[^2]。 - **在构造方法中调用其他构造方法**:使用`this()`可以在一个构造方法中调用同一类的另一个构造方法,通常用于减少代码重复。这必须作为构造方法的第一条语句。 - **示例代码**:在`Teacher`类中,无参构造方法通过`this(name, 0)`调用双参构造方法。 ```java public class Teacher { private String name; private double salary; public Teacher(String name, double salary) { // 双参构造方法 this.name = name; this.salary = salary; } public Teacher(String name) { // 单参构造方法 this(name, 0); // 调用双参构造方法,this()必须是第一行 } } ``` 这避免了初始化逻辑的重复,提高了代码复用性[^4]。 #### 3. 注意事项和最佳实践 - **错误用法**: - 在静态方法中使用`this`会导致编译错误,因为静态方法没有对象实例。 - 过度使用`this`可能降低代码简洁性;只在必要时使用,如变量名冲突时。 - **性能影响**:`this`本身不增加运行时开销,它只是编译时的引用。但在复杂对象中,误用可能导致逻辑错误。 - **与继承的关系**:在子类中,`this`仍指当前对象(可能是子类实例),但访问父类成员时需结合`super`关键字。 #### 4. 总结 `this`关键字是Java面向对象编程的基础工具,主要用于解决变量作用域冲突、简化方法调用和优化构造方法设计。通过合理使用`this`,可以提升代码的健壮性和可维护性。实际开发中,建议在成员变量访问或构造方法链式调用时优先考虑`this`[^1][^2][^4]。 如果您有更多具体场景(如多线程环境),我可以进一步解释。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值