Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
如何理解JavaScript中的this关键字?_创想鸟

如何理解JavaScript中的this关键字?

this的指向取决于函数调用方式,其规则按优先级分为:箭头函数继承外层作用域this;new绑定指向新实例;显式绑定(call/apply/bind)指定this值;隐式绑定指向调用对象;默认绑定指向全局或undefined。

如何理解javascript中的this关键字?

JavaScript中的

this

关键字,说白了,它就是一个函数在执行时,指向的那个“上下文对象”。它的值不是固定不变的,而是完全取决于函数被调用的方式。理解这一点,是掌握

this

的关键。

解决方案

要深入理解

this

,我们需要看清它在不同调用模式下的表现。这就像是

this

有几张不同的面孔,每次函数被调用,它就根据当前的面具来决定自己是谁。

最常见的几种绑定规则包括:

默认绑定 (Default Binding): 当函数作为独立函数被调用,没有明确的上下文对象时,

this

会指向全局对象(在浏览器中是

window

,在Node.js中是

global

)。但在严格模式下,

this

会是

undefined

,这通常是为了防止意外地修改全局对象。

立即学习“Java免费学习笔记(深入)”;

function showThis() {  console.log(this);}showThis(); // 在浏览器中输出 Window 对象,在严格模式下输出 undefined

隐式绑定 (Implicit Binding): 当函数作为对象的方法被调用时,

this

会指向调用它的那个对象。这是我们最常遇到的情况。

const person = {  name: 'Alice',  greet: function() {    console.log(`Hello, my name is ${this.name}`);  }};person.greet(); // 输出 "Hello, my name is Alice",因为 greet 是通过 person 对象调用的

这里有个常见的陷阱:如果把

person.greet

赋值给一个变量,再通过变量调用,就会失去隐式绑定,退化为默认绑定。

const sayHello = person.greet;sayHello(); // 在非严格模式下输出 "Hello, my name is undefined" (或指向全局对象的 name),因为此时 greet 失去了 person 的上下文

显式绑定 (Explicit Binding): 我们可以强制改变

this

的指向,使用

call()

,

apply()

,

bind()

这三个方法。

call()

和

apply()

会立即执行函数,并接受第一个参数作为

this

的值。

call()

接受参数列表,

apply()

接受参数数组。

bind()

则会创建一个新函数,这个新函数的

this

永远被绑定到

bind()

的第一个参数上,它不会立即执行。

function introduce(age, city) {  console.log(`I'm ${this.name}, ${age} years old, from ${city}.`);}const user = { name: 'Bob' };introduce.call(user, 30, 'New York'); // I'm Bob, 30 years old, from New York.introduce.apply(user, [25, 'London']); // I'm Bob, 25 years old, from London.const boundIntroduce = introduce.bind(user, 40);boundIntroduce('Paris'); // I'm Bob, 40 years old, from Paris. (注意这里 bind 也可以预设部分参数)

new

绑定 (New Binding): 当函数作为构造函数,使用

new

关键字调用时,

this

会指向新创建的实例对象。

function Car(make, model) {  this.make = make;  this.model = model;}const myCar = new Car('Honda', 'Civic');console.log(myCar.make); // Hondaconsole.log(myCar.model); // Civic

在这个场景下,

this

指向的是

new

操作符创建的那个空对象,然后构造函数会往这个空对象上添加属性。

箭头函数 (Arrow Functions): 这是ES6引入的,它彻底改变了

this

的绑定方式。箭头函数没有自己的

this

,它会捕获其所在词法作用域(即定义时所处的外部作用域)的

this

值。一旦确定,

this

就不会再改变。

const person = {  name: 'Charlie',  sayLater: function() {    setTimeout(function() {      // 这里的 this 默认指向全局对象 (Window),因为 setTimeout 的回调函数是独立调用的      console.log(`Regular function: ${this.name}`); // undefined 或全局对象的 name    }, 100);  },  sayLaterArrow: function() {    setTimeout(() => {      // 箭头函数捕获了 sayLaterArrow 定义时的 this,也就是 person 对象      console.log(`Arrow function: ${this.name}`); // Charlie    }, 100);  }};person.sayLater();person.sayLaterArrow();

箭头函数在处理回调函数时尤其方便,因为它避免了

this

上下文丢失的问题,省去了我们手动

bind

或

_this = this

的麻烦。

为什么JavaScript中的this总是让人困惑不解?

我记得刚接触JavaScript时,

this

简直就是个谜团。它不像Java或C++那样,

this

总是指向当前实例。JavaScript的

this

更像一个变色龙,它的颜色(指向)完全取决于它被“放在”哪个环境里(如何被调用)。这种动态性是其困惑的根源。

首先,多重绑定规则是主要原因。我们有默认绑定、隐式绑定、显式绑定、

new

绑定,以及后来出现的箭头函数带来的词法绑定。这些规则之间存在优先级,比如显式绑定通常高于隐式绑定,

new

绑定又高于显式绑定。而箭头函数则完全不走寻常路,它直接跳过了所有这些规则,去父级作用域找

this

。这种复杂的优先级和不同寻常的绑定机制,让开发者很难形成一个统一的心智模型。

其次,回调函数的上下文丢失是另一个常见的痛点。在异步操作(如

setTimeout

、事件监听器)或数组方法(如

forEach

、

map

)中,如果直接传入一个包含

this

的普通函数作为回调,

this

往往会退化为默认绑定,指向全局对象(或

undefined

),而不是我们期望的那个对象。这导致很多初学者不得不使用

const self = this

或者

.bind(this)

来“固定”

this

,这本身就说明了其复杂性。

再者,严格模式的影响也增加了理解难度。在非严格模式下,默认绑定会指向全局对象,这有时会掩盖问题。但在严格模式下,默认绑定会是

undefined

,这会让错误暴露得更早,但也可能让不熟悉规则的开发者感到更困惑。

对我来说,真正理解

this

,是从放弃“

this

是一个固定指针”的观念开始的。它更像是一个“运行时上下文引用”,每次函数执行前,JavaScript引擎都会计算出它应该指向谁。

如何在不同场景下正确判断this的指向?

判断

this

的指向,其实可以遵循一个相对清晰的“决策树”或者说“优先级列表”。当你看到一个函数调用时,可以这样一步步地问自己:

是不是箭头函数?

如果是,那么

this

就不是由调用方式决定的。它会向上寻找定义它的那个最近的非箭头函数作用域(或者全局作用域),并继承那个作用域的

this

。一旦确定,永不改变。如果不是,继续下一步。

是不是通过

new

关键字调用的?

如果是(例如

new MyConstructor()

),那么

this

会指向新创建的那个对象实例。如果不是,继续下一步。

是不是通过

call()

、

apply()

或

bind()

显式调用的?

如果是(例如

myFunction.call(someObject, ...)

),那么

this

会指向传入的第一个参数(

someObject

)。如果传入

null

或

undefined

,则会退化为默认绑定(指向全局对象或

undefined

)。如果不是,继续下一步。

是不是作为对象的方法调用的?

如果是(例如

myObject.myMethod()

),那么

this

会指向调用这个方法的那个对象(

myObject

)。注意,这里只看

.

前面的那个对象。如果不是,继续下一步。

默认绑定:

如果以上都不是,那么就是默认绑定。在非严格模式下,

this

指向全局对象(浏览器中的

window

,Node.js中的

global

)。在严格模式下,

this

是

undefined

。

这个流程图能帮助我们覆盖绝大多数情况。举个例子:

const obj = {  name: 'Tester',  method: function() {    console.log(this.name);  },  arrowMethod: () => {    console.log(this.name); // 这里的 this 捕获的是 obj 定义时的全局 this,所以是 undefined 或 Window.name  }};obj.method(); // 步骤4:隐式绑定,this 指向 obj -> 'Tester'const func = obj.method;func(); // 步骤5:默认绑定,this 指向全局对象 -> undefined 或 Window.nameconst anotherObj = { name: 'Another' };obj.method.call(anotherObj); // 步骤3:显式绑定,this 指向 anotherObj -> 'Another'obj.arrowMethod(); // 步骤1:箭头函数,this 捕获定义时的全局 this -> undefined 或 Window.name

通过这种逐层判断,你可以更系统地分析

this

的指向。

箭头函数如何改变了this的工作方式?

箭头函数是ES6带来的一项革命性特性,它在

this

的处理上采取了一种全新的策略:词法绑定。这意味着箭头函数没有自己的

this

,它的

this

值完全取决于它被定义时所处的外部(词法)作用域。一旦定义,

this

的指向就固定了,不会因为函数后续的调用方式而改变。

这与传统的

function

关键字定义的函数形成了鲜明对比。普通函数在执行时,

this

是动态绑定的,它的值由函数被调用的方式决定。而箭头函数则像一个“旁观者”,它不参与

this

的绑定过程,只是“借用”了父级作用域的

this

。

核心改变:

解决了回调函数中的

this

丢失问题: 这是箭头函数最显著的优势之一。在ES5及之前,我们经常需要在异步回调(如

setTimeout

)、事件处理器或数组迭代方法中,手动保存

this

的引用(例如

var self = this;

),或者使用

bind()

方法来确保

this

指向正确。箭头函数通过词法绑定,自然而然地解决了这个问题。

class Greeter {  constructor(name) {    this.name = name;  }  // 传统函数,this 在 setTimeout 回调中会丢失  greetOld() {    setTimeout(function() {      console.log(`Hello from old way, ${this.name}`); // this 指向 Window/undefined    }, 100);  }  // 箭头函数,this 捕获了 greetNew 方法定义时的 this (即 Greeter 实例)  greetNew() {    setTimeout(() => {      console.log(`Hello from new way, ${this.name}`); // this 指向 Greeter 实例    }, 100);  }  // 也可以直接将类方法定义为箭头函数,这样它的 this 总是指向实例  greetMethod = () => {    console.log(`Hello from arrow method, ${this.name}`);  }}const myGreeter = new Greeter('World');myGreeter.greetOld(); // 输出 "Hello from old way, undefined"myGreeter.greetNew(); // 输出 "Hello from new way, World"myGreeter.greetMethod(); // 输出 "Hello from arrow method, World"setTimeout(myGreeter.greetMethod, 200); // 即使作为回调,this 也保持不变

更简洁的代码: 避免了冗余的

bind

调用或

self = this

的赋值,代码更加简洁易读。

不能作为构造函数: 箭头函数不能使用

new

关键字调用,因为它没有自己的

this

,也就无法为新对象绑定

this

。

没有

arguments

对象: 箭头函数也没有自己的

arguments

对象,它会从父级作用域继承

arguments

。

不适用于定义对象方法: 如果你希望对象方法中的

this

指向该对象本身,那么使用普通函数定义方法是更合适的。如果使用箭头函数,

this

会指向对象定义时所处的外部作用域(通常是全局对象),这可能不是你想要的。

const myObject = {  value: 42,  getValue: function() {    return this.value; // this 指向 myObject  },  getArrowValue: () => {    return this.value; // this 指向全局对象(Window/undefined),而非 myObject  }};console.log(myObject.getValue());      // 42console.log(myObject.getArrowValue()); // undefined (或 Window.value)

总的来说,箭头函数提供了一种更可预测、更稳定的

this

行为,极大地简化了JavaScript中处理上下文绑定的复杂性,尤其是在涉及回调和高阶函数时。但理解它的工作原理,以及何时应该使用它,何时不应该,仍然是关键。

以上就是如何理解JavaScript中的this关键字?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1520868.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
什么是Web存储的localStorage和sessionStorage,以及它们在与服务端协同时的安全注意事项有哪些?
上一篇 2025年12月20日 13:42:30
JavaScript 循环创建单选框并赋予不同值
下一篇 2025年12月20日 13:42:45

相关推荐

发表回复

登录后才能评论
关注微信