《JavaScript this 指向深度剖析:从基础到复杂场景实战》

前言

大家好,之前作者写过一篇文章:深入理解JavaScript的this关键字,分析了this的基本概念,以及绑定规则,但this是面试中的一个重难点,所以本文通过两道分析this指向的复杂题来巩固我们的this知识,特别是第二道题,还涉及到行为委托的知识,大家可以往下看,看看是否能做出来!

题目一

一个能够将背景颜色变绿的按钮。

html

html 复制代码
<button class="button">点击变色</button>
    <script src="./button.js">
        new Button('button');
    </script>

button.js

js 复制代码
function Button(id){ //1.请分析下面两个this是指什么,为什么?
    this.element = document.querySelector(`#${id}`); 
    this.bindEvent();
}

Button.prototype.bindEvent = function() { //2.请分析下面的this是指什么,为什么?
    this.element.addEventListener('click', this.setBgColor.bind(this))
}

Button.prototype.setBgColor = function(){ //3.请分析下面的this是指什么,为什么?
    this.element.
}

让我们进行仔细分析:

1. Button 构造函数中的 this

js 复制代码
function Button(id) {
    this.element = document.querySelector(`#${id}`); 
    this.bindEvent();
}

this 指向 :新创建的 Button 实例对象
原因 :当使用 new Button('button') 调用时,new 操作符会:

  1. 创建一个新的空对象
  2. 将这个新对象的原型指向 Button.prototype
  3. 将这个新对象绑定到构造函数中的 this
  4. 执行构造函数中的代码
  5. 返回这个新对象(除非构造函数返回另一个对象)

2. bindEvent 方法中的 this

js 复制代码
Button.prototype.bindEvent = function() {
    this.element.addEventListener('click', this.setBgColor.bind(this)) 
}

this 指向 :Button 实例对象
原因 :当通过实例调用 bindEvent() 方法时(如 this.bindEvent()),方法内部的 this 会隐式绑定到调用它的对象(即 Button 实例)。这是 JavaScript 的方法调用规则。

3. setBgColor 方法中的 this

js 复制代码
Button.prototype.setBgColor = function() {
    this.element.
}

this 指向 :Button 实例对象
原因:这里有两个关键点:

  1. bindEvent() 中使用了 .bind(this)setBgColor 的 this 显式绑定到了当前的 Button 实例

  2. 通过 .bind(this) 我们确保了无论 setBgColor 如何被调用,this 都指向 Button 实例

注意:如果没有bind(this)会怎么样?

如果去掉 .bind(this),代码会变成这样:

js 复制代码
Button.prototype.bindEvent = function() {
    this.element.addEventListener('click', this.setBgColor) // 去掉了 .bind(this)
}
  1. setBgColor 中的 this 将不再指向 Button 实例
    当点击事件触发时,this.setBgColor 作为事件处理函数被调用,由于在addEventListener内,所以此时的 this 会默认指向触发事件 的 DOM 元素(即 <button> 元素),而不是 Button 实例。
  2. 代码会报错
    setBgColor 方法中尝试访问 this.element 时,因为 this 现在是 <button> 元素,而 <button> 元素没有 element 属性,所以会抛出类似这样的错误:
    Uncaught TypeError: Cannot read property 'style' of undefined

好了,题目1结束了,看看你的分析是否是正确的吧!这题里的this绑定规则用到了隐式绑定,显式绑定,new绑定以及事件触发事件时的this绑定等,是一道复杂的题目。

题目二

这道题涉及到JS中的行为委托的委托理论,是来自于《你不知道的JavaScript》里的例题,当时作者第一次分析时,会把this和原型链给搞混,大家可以来做一下

js 复制代码
Foo = { 
    init: function(who) {  //1.分析init里面的this
        this.me = who;
    },
    identify: function(){  //2.分析identify里面的this
        return "Im" + this.me;
    }
};

Bar = Object.create(Foo);

Bar.speak = function() { //3.分析这里面的this
    console.log('hello',this.identify() + ".");
}

var b1 = Object.create(Bar);
b1.init("zhangsan");
b1.speak();

让我们逐步分析这段代码中的 this 绑定情况:

首先注意,这里b1 = Object.create(Bar) 是创建 b1 对象,并为b1对象设置原型链,这里注意区分new的方式,他不会调用构造函数。它不像new方式,刚开始就会指定this,它刚开始不会指定任何this,只有在后面方法调用时才会绑定this。

1. init 方法中的 this

js 复制代码
init: function(who) {
    this.me = who;  // 这里的 this 指向b1
}

分析

  • 当通过 b1.init("zhangsan") 调用时
  • init 是作为 b1 对象的方法被调用的
  • 根据隐式绑定规则,方法中的 this 指向调用它的对象
  • this 指向b1 对象

2. identify 方法中的 this

js 复制代码
identify: function() {
    return "Im" + this.me;  // 这里的 this 也指向b1
}

分析

  • 当通过 this.identify()speak 方法中调用时
  • identify 是作为 this(即 b1 对象)的方法被调用的
  • 根据隐式绑定规则,方法中的 this 指向调用它的对象
  • this 指向b1 对象

3. speak 方法中的 this

js 复制代码
speak: function() {
    console.log('hello', this.identify() + ".");  // 这里的 this 指向
}

分析

  • 当通过 b1.speak() 调用时
  • speak 是作为 b1 对象的方法被调用的
  • 根据隐式绑定规则,方法中的 this 指向调用它的对象
  • this 指向b1 对象

所以你会发现这三个this都是指向b1,原型链只是帮我们分析要调用哪个函数,分析this只用关注是谁调用的就行!请看下面的完整执行流程

完整执行流程

  1. b1 = Object.create(Bar) 创建 b1 对象,继承 Bar 的原型链

  2. b1.init("zhangsan") 调用:

    • init 中的 this 指向 b1
    • 设置 b1.me = "zhangsan"
  3. b1.speak() 调用:

    • speak 中的 this 指向 b1
    • 调用 this.identify()(即 b1.identify()
    • identify 中的 this 也指向 b1
    • 返回 "Imzhangsan"
    • 最终输出:hello Imzhangsan.

原型链关系

js 复制代码
b1 -> Bar -> Foo

好了,题目二结束了,我们需要注意这道题中,Object.create()的作用,分析this时,只要看最后的调用位置即可!

总结

JavaScript 中的 this 机制是语言的核心特性之一,也是开发者必须掌握的难点。通过本文两道经典题目的分析, 我们可以理解 this 的关键在于:它不是在定义时确定的,而是在调用时根据执行上下文动态绑定的。掌握这一核心原则,配合本文的分析方法,就能在各种复杂场景中准确判断 this 指向。通过不断练习和思考,this 将不再是令人头疼的问题,而会成为你灵活运用 JavaScript 的强大工具

相关推荐
慧一居士8 分钟前
flex 布局完整功能介绍和示例演示
前端
DoraBigHead10 分钟前
小哆啦解题记——两数失踪事件
前端·算法·面试
一斤代码6 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子6 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年6 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子6 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina6 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路7 小时前
React--Fiber 架构
前端·react.js·架构
coderlin_7 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
伍哥的传说7 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js