javascript this(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

在 JavaScript 开发中,"this" 是一个既基础又复杂的概念。它像一条隐形的线索,贯穿于函数调用、对象方法、构造函数和箭头函数等场景中。对于编程初学者来说,"this" 的行为往往令人困惑,而中级开发者也时常需要回顾其规则以避免错误。本文将通过 循序渐进 的方式,结合 形象比喻代码示例,深入解析 "javascript this" 的核心逻辑,帮助开发者建立清晰的理解框架。


一、基础概念:this 是什么?

JavaScript 中的 this 是一个 指向上下文环境的指针,其值并非在函数定义时确定,而是在函数执行时由调用方式决定。可以将其想象为 "当前环境的代号"

  • 全局作用域中的 this 指向 全局对象(浏览器中为 window,Node.js 中为 global)。
  • 函数内部的 this 则根据调用方式动态变化。

案例 1:全局作用域中的 this

console.log(this); // 浏览器中输出 Window 对象  
function globalFunc() {  
  console.log(this === window); // true  
}  
globalFunc();  

二、函数调用中的 this 规则

函数调用的 四种常见场景 决定了 this 的指向:

  1. 普通函数调用this 指向全局对象(严格模式下为 undefined)。
  2. 方法调用this 指向 调用该方法的对象
  3. 构造函数调用this 指向 新创建的实例对象
  4. 显式绑定:通过 call()apply()bind() 明确指定 this

1. 普通函数调用

function simpleFunc() {  
  console.log(this); // 全局对象或 undefined(严格模式)  
}  
simpleFunc();  

2. 方法调用

const obj = {  
  name: "对象方法",  
  sayName() {  
    console.log(this.name); // 输出 "对象方法"  
  }  
};  
obj.sayName();  

3. 构造函数调用

function Person(name) {  
  this.name = name; // this 指向新创建的实例  
}  
const p = new Person("Alice");  
console.log(p.name); // "Alice"  

4. 显式绑定

const target = { value: 42 };  
function demo() {  
  console.log(this.value); // 42  
}  
demo.call(target); // 显式绑定到 target 对象  

三、箭头函数对 this 的影响

箭头函数是 ES6 引入的特性,其 最大的特性之一是没有自己的 this,而是继承外层函数的 this。这使得箭头函数在回调函数或嵌套函数中更为简洁,但也需要开发者谨慎处理上下文绑定。

案例 2:普通函数 vs 箭头函数

const obj = {  
  value: 100,  
  method: function() {  
    setTimeout(function() {  
      console.log(this.value); // undefined(普通函数 this 指向全局对象)  
    }, 100);  
  },  
  arrowMethod: function() {  
    setTimeout(() => {  
      console.log(this.value); // 100(箭头函数继承外层 this)  
    }, 100);  
  }  
};  
obj.method();  
obj.arrowMethod();  

四、复杂场景解析:this 的动态性

1. 链式调用中的 this

当函数返回 this 时,可以实现 方法链调用。例如:

const calculator = {  
  value: 0,  
  add(n) {  
    this.value += n;  
    return this; // 返回 this 实现链式调用  
  },  
  subtract(n) {  
    this.value -= n;  
    return this;  
  }  
};  
calculator.add(5).subtract(3); // 最终 value 为 2  

2. 事件处理中的 this

在浏览器事件中,this 通常指向触发事件的 DOM 元素。例如:

<button id="btn">点击我</button>  
document.getElementById("btn").addEventListener("click", function() {  
  console.log(this); // 输出按钮元素  
});  

3. 混合调用的优先级

当函数同时作为方法和构造函数调用时,需注意优先级。例如:

function Confusing() {  
  this.name = "构造函数";  
  this.print = function() {  
    console.log(this.name); // 调用时 this 由方法调用决定  
  };  
}  
const instance = new Confusing();  
instance.print(); // 输出 "构造函数"  

五、常见错误与解决方案

1. 丢失 this 的场景

当函数脱离对象调用时,this 可能丢失预期值。例如:

const obj = {  
  value: 10,  
  compute: function() {  
    return function() {  
      return this.value; // this 指向全局对象或 undefined  
    };  
  }  
};  
console.log(obj.compute()()); // undefined  

解决方案:使用箭头函数或显式绑定:

compute: function() {  
  return () => {  
    return this.value; // 继承外层 this  
  };  
},  

2. 构造函数未返回 this

如果在构造函数中显式 return 非对象值,new 关键字会忽略返回值,但若返回一个对象,则 this 将指向该对象。例如:

function BrokenConstructor() {  
  this.value = 42;  
  return { value: 100 }; // 返回对象会覆盖默认行为  
}  
const broken = new BrokenConstructor();  
console.log(broken.value); // 100(而非 42)  

六、实践技巧与总结

1. 开发中的调试方法

  • 在函数开头添加 console.log(this) 查看当前上下文。
  • 使用 严格模式"use strict")避免全局 this 指向问题。
  • 对复杂逻辑使用箭头函数或 bind() 明确绑定 this

2. this 的核心规则速记表

调用方式this 指向
普通函数调用全局对象(严格模式为 undefined
方法调用调用该方法的对象
构造函数调用新创建的实例对象
显式绑定(call/apply/bind指定的第一个参数对象
箭头函数继承外层函数的 this

结论

掌握 "javascript this" 的关键是理解其 动态性绑定规则。通过本篇文章的案例和比喻,开发者可以逐步建立对 this 的直观认知。建议在实际开发中,通过以下方式巩固知识:

  1. 为每个函数调用场景明确标注 this 的预期指向;
  2. 使用箭头函数简化上下文传递;
  3. 对复杂逻辑进行单元测试,验证 this 的行为。

掌握 this 将显著提升 JavaScript 代码的健壮性,尤其在处理异步操作、事件处理和面向对象编程时。希望本文能成为你理解这一核心概念的坚实起点!

最新发布