【最简单最全面】一文讲清楚五大this指向,this到底指向哪里?

目录

【最简单最全面】一文讲清楚五大this指向,this到底指向哪里?

一、this是什么?

二、五大情境下的this指向

1、默认绑定(函数独立调用)

2、隐式绑定(对象调用)

3、显式绑定(call/apply/bind)

4、new 绑定(构造函数)

5、箭头函数绑定

三、判断this指向的3步心法(实战)

四、易出错的场景

1、this 被丢失

2、在事件监听器中

五、总结图解

六、结语


        作者:watermelo37

        CSDN万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者,全平台博客昵称watermelo37。

        一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。

---------------------------------------------------------------------

温柔地对待温柔的人,包容的三观就是最大的温柔。

---------------------------------------------------------------------

【最简单最全面】一文讲清楚五大this指向,this到底指向哪里?

一、this是什么?

        this 是 JavaScript 中最迷惑、最核心的概念之一。它的值不是取决于函数在哪声明的,而是取决于它是如何被调用的。

        简单来说,this 是函数运行时自动创建的一个特殊变量,它指向调用该函数的“拥有者”对象。但它的指向受不同的调用方式影响,我们一起来理一理五大this指向的情况。

二、五大情境下的this指向

1、默认绑定(函数独立调用)

        如果是函数直接使用this,那么this在浏览器环境下指向window,但在严格模式下 this === undefined,而不是 window。

function showThis() {
  console.log(this);
}
showThis(); // 浏览器环境下:this -> window

2、隐式绑定(对象调用)

        如果含有this的函数在对象里面,那么就看谁在点号前,this 就指谁。这里user调用了含有this的greet方法,所以this指向就是user。

const user = {
  name: 'Alice',
  greet() {
    console.log(this.name);
  }
};
user.greet(); // this -> user,输出 "Alice"

3、显式绑定(call/apply/bind)

        关于apply和call不熟悉的可以看看这篇:改变函数调用上下文:apply与call方法详解及实例

        call/apply/bind这三个都是用来改变this指向的,其区别在于:call、apply会立即调用,指定 this,bind返回新函数,this 永远被绑定。

function greet() {
  console.log(this.name);
}
const person = { name: 'Bob' };

greet.call(person);  // this -> person,输出 "Bob"
greet.apply(person); // 同上
const bound = greet.bind(person);
bound();             // 同上

4、new 绑定(构造函数)

        用 new 创建对象时,this 指向这个新对象。

function Person(name) {
  this.name = name;
}
const p = new Person('Charlie'); // this -> 新创建的对象
console.log(p.name); // Charlie

5、箭头函数绑定

        这个应该是最难的一类了,很多人一直搞不清楚箭头函数的特殊性,也不理解特殊性是为了做什么。箭头函数没有自己的 this,它会继承外层作用域的 this,这样有助于其在回调或者事件里面能获得有用的this指向。

const person = {
  name: 'Eva',
  greet() {
    setTimeout(() => {
      console.log(this.name); // "Eva",因为箭头函数继承了外部 this
    }, 1000);
  }
};
person.greet();

三、判断this指向的3步心法(实战)

        按照如下三步依次判断即可:

  1. 有没有箭头函数? 👉 是的话,往上找作用域!

  2. 谁在调用这个函数? 👉 看点号前是谁

  3. 有没有 call/apply/bind 或 new? 👉 有就以指定对象为准

四、易出错的场景

1、this 被丢失

        虽然 fn = obj.say 是从对象上“取出”方法,但 你调用 fn() 时,它是作为一个“普通函数”调用的,没有上下文绑定。

        换句话说,它“脱离”了原本属于它的对象环境,默认绑定规则生效,this 就变成了 window(或 undefined,在严格模式下)。

        按照先前提出的隐式绑定“谁点它this就指向谁”,这里直接调用 fn() 效果等同 window.fn(),所以this指向就变成了window。

const obj = {
  name: 'Foo',
  say() {
    console.log(this.name);
  }
};
const fn = obj.say;
fn(); // this -> window (或 undefined)

        解决方案:用.bind(obj) 或箭头函数包装。

const fn = obj.say.bind(obj);
fn(); // this 始终是 obj

const fn = () => obj.say();
fn(); // this -> obj.say() 的 this 正常

2、在事件监听器中

        注意回调函数不同的写法this指向不同,直接写普通函数一般是为了修改DOM元素,比如this.style.backgroundColor = 'red'。写箭头函数一般是为了获取外层的数据、实例对象、上下文等,更常见。

const btn = document.querySelector('button');
btn.addEventListener('click', function () {
  console.log(this); // this -> 当前 DOM 元素(btn)
});

btn.addEventListener('click', () => {
  console.log(this); // this -> 外部作用域(可能是 window)
});

五、总结图解

调用方式this 指向
普通函数

window(或 undefined,严格模式)

对象方法调用该方法的对象
call/apply/bind明确指定的对象
构造函数新创建的对象
箭头函数定义时所在作用域的 this

六、结语

        this 是动态的,取决于调用方式。箭头函数没有自己的 this,这是最常见的坑,掌握了这 5 条规则,配合调试/打印,基本能搞定 99% 场景。

        只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

        其他热门文章,请关注:

        极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

        你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

        DeepSeek:全栈开发者视角下的AI革命者

        通过array.filter()实现数组的数据筛选、数据清洗和链式调用

        通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能

        TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急

        通过MongoDB Atlas 实现语义搜索与 RAG——迈向AI的搜索机制

        深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解

        el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

        MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver

        JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、DOM操作等

        前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略

        高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图

        干货含源码!如何用Java后端操作Docker(命令行篇)

        在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境

        Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具

<think>好的,我现在需要给用户讲解清楚JavaScript中的class类。首先,我得回忆一下自己对这个主题的理解,确保没有遗漏或者错误的地方。嗯,JavaScript的class是在ES6引入的,它主要是基于原型继承的语法糖,对吧?所以它的底层还是原型链,但语法更接近传统面向对象语言,比如Java或C++,这样更容易让开发者理解和组织代码。 接下来,我应该从基础开始。首先解释class的基本结构,比如如何声明一个类,构造函数constructor的作用,以及如何定义方法。用户可能需要一个简单的例子,比如定义一个Person类,有name属性和sayHello方法。这时候要注意语法,使用class关键字,constructor方法,以及普通方法。 然后,需要讨论继承,也就是extends关键字。这里要提到super的作用,在派生类中调用父类的构造函数。可能还需要举例,比如Student类继承Person类,并添加自己的属性如grade和方法study。这个例子能帮助用户理解继承的用法和super的重要性。 接下来是静态方法和静态属性。静态方法是属于类本身的方法,而不是实例,所以要用static关键字。比如在Person类中添加一个静态方法compare,比较两个人的年龄。这里需要强调静态方法不能通过实例调用,而是通过类名直接调用。 还有私有字段,这是ES2022引入的特性,用#前缀表示。比如在类中定义#age,这样外部无法直接访问,只能通过公共方法来获取或修改。这个例子能说明封装的概念,但要注意浏览器兼容性问题。 然后,需要对比class和原型继承的区别,说明class只是语法糖,底层还是基于原型的。可能用代码例子展示传统的构造函数和原型方法,与class写法对比,让用户明白两者本质相同,但class更简洁易读。 可能用户还会关心class的一些高级特性,比如getter和setter,或者类表达式。不过作为入门介绍,可能暂时不需要深入这些细节,但可以稍微提一下,让用户知道有这些功能存在。 还要注意常见问题,比如类声明不会提升,必须先定义后使用,而函数声明会提升。此外,类的方法之间不需要逗号分隔,这点和对象字面量不同,容易出错,需要提醒用户。 后,总结class的优势:代码结构清晰,易于继承,更接近传统OOP,适合中大型项目。但也要指出其局限性,比如私有字段的兼容性问题,以及无法直接多继承等。 在组织内容时,要确保结构清晰,分点讲解,每个部分都有代码示例,帮助用户逐步理解。同时,检查LaTeX格式是否正确,行内公式用$...$,独立公式用$$...$$,不过在这个问题中可能数学公式不多,但如果有提到数学相关的例子,比如计算类实例的数量,可能需要用到。不过当前主题是JavaScript的class,可能数学公式较少,但需要确认是否有必要。 在写作过程中,要使用中文,保持口语化,避免使用专业术语过多,或者解释清楚术语。比如“语法糖”这样的术语,可能需要简单解释一下,让新手也能理解。 现在,检查是否有遗漏点,比如类的访问器属性(getter和setter),或者类的表达式(匿名类),这些可以作为扩展内容,但如果是“一文讲清楚”,可能需要涵盖。不过根据用户要求,可能需要保持简洁,重点突出核心概念。 后,确保所有代码示例正确,符合JavaScript语法,比如类名首字母大写,方法定义不用function关键字,正确使用super等。如果有错误,可能会误导用户,所以需要仔细检查。 总结下来,结构应该是: 1. Class基本概念 2. 基本结构(constructor、方法) 3. 继承(extends、super) 4. 静态方法和属性 5. 私有字段 6. Class与原型继承的关系 7. 注意事项和常见问题 8. 总结优缺点 每个部分配合代码示例,确保用户能一步步理解。同时,注意用户可能存在的疑问点,比如为什么使用class而不是原型,或者如何处理私有变量,需要提前解答。</think>好的,我将通过以下步骤带您理解JavaScript中的`class`类。本文结构清晰,代码示例丰富,适合新手入门。 --- ### 一、Class的基本概念 JavaScript的`class`是**ES6引入的语法糖**,本质仍是基于原型的继承,但写法更接近传统面向对象语言(如Java),解决了ES5构造函数和原型链写法冗长的问题。 --- ### 二、Class基本结构 #### 1. 定义类与构造函数 ```javascript class Person { constructor(name) { this.name = name; // 实例属性 } // 实例方法(添加到原型链) sayHello() { console.log(`你好,我是${this.name}`); } } // 使用类 const person = new Person("小明"); person.sayHello(); // 输出:你好,我是小明 ``` #### 2. 静态方法 用`static`定义,直接通过类名调用: ```javascript class MathUtils { static sum(a, b) { return a + b; } } console.log(MathUtils.sum(2, 3)); // 输出:5 ``` --- ### 三、继承(extends和super) #### 1. 基础继承 ```javascript class Student extends Person { constructor(name, grade) { super(name); // 调用父类构造函数 this.grade = grade; } study() { console.log(`${this.name}正在学习${this.grade}年级课程`); } } const student = new Student("小红", 6); student.sayHello(); // 继承自Person student.study(); // 输出:小红正在学习6年级课程 ``` #### 2. 重写方法 ```javascript class Student extends Person { sayHello() { super.sayHello(); // 调用父类方法 console.log("我是一名学生"); } } ``` --- ### 四、私有字段(ES2022) 使用`#`前缀定义私有属性,外部无法直接访问: ```javascript class User { #password; // 私有字段 constructor(username, password) { this.username = username; this.#password = password; } checkPassword(inputPwd) { return this.#password === inputPwd; } } const user = new User("admin", "123456"); console.log(user.#password); // 报错:私有字段无法访问 console.log(user.checkPassword("123456")); // true ``` --- ### 五、Class vs 原型继承 #### 传统ES5写法 ```javascript function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log("Hello, " + this.name); }; ``` #### ES6 Class写法(等价但更简洁) ```javascript class Person { constructor(name) { this.name = name; } sayHello() { console.log(`Hello, ${this.name}`); } } ``` --- ### 六、注意事项 1. **类声明不会提升**:必须先声明后使用。 2. **方法不用逗号分隔**:类方法之间无需`,`,与对象字面量不同。 3. **严格模式**:类内部默认启用严格模式。 --- ### 七、总结 #### 优点 - 代码结构清晰,易于实现继承 - 更接近传统OOP,降低学习成本 - 适合中大型项目代码组织 #### 局限 - 私有字段(`#`)存在兼容性问题 - 底层仍是原型链,无法直接实现多继承 --- 通过以上内容,您应该能掌握JavaScript类的核心用法。如需深入,可继续探索`getter/setter`、`Mixin模式`等高级特性。
评论 104
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值