《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 的强大工具

相关推荐
电商数据girl14 分钟前
【经验分享】浅谈京东商品SKU接口的技术实现原理
java·开发语言·前端·数据库·经验分享·eclipse·json
Senar30 分钟前
听《富婆KTV》让我学到个新的API
前端·javascript·浏览器
烛阴1 小时前
提升Web爬虫效率的秘密武器:Puppeteer选择器全攻略
前端·javascript·爬虫
hao_wujing1 小时前
Web 连接和跟踪
服务器·前端·javascript
前端小白从0开始2 小时前
前端基础知识CSS系列 - 04(隐藏页面元素的方式和区别)
前端·css
想不到耶2 小时前
Vue3轮播图组件,当前轮播区域有当前图和左右两边图,两边图各显示一半,支持点击跳转和手动滑动切换
开发语言·前端·javascript
萌萌哒草头将军2 小时前
🚀🚀🚀尤雨溪:Vite 和 JavaScript 工具的未来
前端·vue.js·vuex
Fly-ping2 小时前
【前端】cookie和web stroage(localStorage,sessionStorage)的使用方法及区别
前端
我家媳妇儿萌哒哒3 小时前
el-upload 点击上传按钮前先判断条件满足再弹选择文件框
前端·javascript·vue.js