JavaScript中this指向的六种场景与解决方案

作者:闭包旅人时间:2026-10-23 01:14:24浏览:571

本文系统总结JavaScript中this指向的六种核心场景:全局调用、对象方法、DOM事件、构造函数、ES6箭头函数以及通过call/apply/bind强制改变指向。重点解析非严格与严格模式下的差异,以及箭头函数词法作用域对this绑定的影响,并提供解决内部函数this丢失的实用技巧。

JavaScript this指向基础规则

在JavaScript开发中,this的指向机制往往是初学者乃至有经验的开发者容易困惑的难点,也是各类前端面试中的高频考点。为了清晰掌握这一概念,我们需要先明确几个基础规则。

第一,全局变量默认挂载在window对象之下。

第二,在常规函数调用中,this通常指向其调用者。

第三,在ES6引入的箭头函数中,this指向定义时的创建者(词法作用域),而非调用者。

第四,可以通过call、apply和bind这三个方法人为地改变函数的this指向。

接下来,我们将结合具体代码场景对上述规则进行详细分析。

普通函数与严格模式下的this

第一种情况:普通函数调用。

在非严格模式下,


const func = function () {
    console.log(this);
    const func2 = function () {
      console.log(this);
    };
    func2(); //Window
  };
  func(); //Window

在严格模式下,


'use strict'
  const func = function () {
    console.log(this);
    const func2 = function () {
      console.log(this);
    };
    func2(); //undefined
  };
  func(); //undefined

综合第四与第一条规则:func为全局函数,默认挂载于window对象,其this指向调用者window,故输出window对象。但在严格模式下,this禁止指向全局变量window,因此输出undefined(func2在直接调用时默认指向全局window,此属JavaScript设计缺陷;理想设计应为内部函数this绑定至外层函数对应对象。为规避此缺陷,程序员采用变量替代法,约定俗成命名为that,该方法后续将详述)。

对象方法中的this与解决方案

第二种情况:作为对象方法调用。


const user = {

    userName: '小张',
    age: 18,
    selfIntroduction: function () {
      const str = '我的名字是:' + this.userName + ",年龄是:" + this.age;
      console.log(str);

      const loop = function () {
        console.log('我的名字是:' + this.userName + ",年龄是:" + this.age);
      };

      loop();   //我的名字是:undefined,年龄是:undefined

    }
  };

  user.selfIntroduction();  //我的名字是:小张,年龄是:18

根据规则一,this指向其调用者。在selfIntroduction()方法中,调用者是user对象,因此方法内部的this指向父对象user。然而,在selfIntroduction内部定义的loop函数输出undefined,原因在于JavaScript的设计特性:内部函数loop是独立调用的,其this并未绑定到user上。针对这种情况,通常的解决方案是在selfIntroduction方法内部将this缓存下来,传递给内部函数使用。


const user = {
    userName: '小张',
    age: 18,
    selfIntroduction: function () {
      const str = '我的名字是:' + this.userName + ",年龄是:" + this.age;
      console.log(str);

      const that=this;

      const loop = function () {
        console.log('我的名字是:' + that.userName + ",年龄是:" + that.age);
      };

      loop();   //我的名字是:小张,年龄是:18

    }
  };

  user.selfIntroduction();  //我的名字是:小张,年龄是:18

经过上述处理后,loop函数的this指向便符合预期。


const user={

    userName:'小张',
    age:18,
    selfIntroduction:function(){
      const str='我的名字是:'+this.userName+",年龄是:"+this.age;
      console.log(str); 
    }
  };

  const other =user.selfIntroduction;
  other(); //我的名字是:undefined,年龄是:undefined

  const data={
    userName:'小李',
    age:19,
  };
  data.selfIntroduction=user.selfIntroduction;
  data.selfIntroduction(); //我的名字是:小李,年龄是:19

再看另一段代码:将selfIntroduction方法赋值给全局变量other后调用other()。由于other挂载在全局window对象下,而window对象中不存在userName和age属性,因此输出undefined。第二段代码中,声明了data对象并包含username和age属性。根据规则二,this指向调用者,此时data是selfIntroduction的调用者,因此成功输出了data对象的userName和age属性。

事件处理中的this指向

第三种情况:在HTML中作为事件触发器。


<body>
  <div id="btn">点击我</div>
</body>
     const btn=document.getElementById('btn');
    btn.addEventListener('click',function () {
      console.log(this); //<div id="btn">点击我</div>
    })

这种情况同样遵循规则二,即this指向调用者。在事件处理函数中,this指向触发事件的事件源元素(event target)。

构造函数中的this绑定

第四种情况:使用new关键字(构造函数)。


const fun=function(userName){
    this.userName=userName;
  }
  const user=new fun('郭德纲');  
  console.log(user.userName); //郭德纲

new关键字会构造一个对象实例,并将其赋值给user变量。因此,构造函数内部的this指向新创建的user对象,userName随之成为user对象的属性。

ES6箭头函数的this特性

第五种情况:ES6箭头函数。


const func1=()=>{
    console.log(this); 
  };
  func1(); //Window
const data={
    userName:'校长',
    selfIntroduction:function(){
      console.log(this); //Object {userName: "校长", selfIntroduction: function}
      const func2=()=>{
        console.log(this); //Object {userName: "校长", selfIntroduction: function}
      }

      func2();
    }
  }
  data.selfIntroduction();

回顾开头提到的规则三:在ES6箭头函数中,this指向定义时的创建者,而非调用者。fun1在全局作用域下创建,因此其this指向全局window;而fun2在对象data的方法中创建,其this指向data对象。因此,在func2函数内部,this指向data对象。个人认为,ES6箭头函数的this绑定机制是对前述JavaScript设计缺陷的一种改进。

使用call/apply/bind改变this

第六种情况:改变this的指向。

call、apply和bind这三个方法允许开发者人为地改变函数的this指向。关于这三者的具体区别,将在后续文章中详细解释。此处先以其中一个为例进行说明。


const func=function(){
   console.log(this);
 }; 
 func(); //window
 func.apply({userName:"郭德纲"}); //Object {userName: "郭德纲"}

这三个方法均能改变this指向,区别在于:call和apply在绑定this后会立即执行该方法,而bind方法会返回一个新的可执行函数,不会立即执行。

综上所述,核心要点即开头提到的四点。

1. 全局变量默认挂载在window对象下。

2. 一般情况下,this指向它的调用者。

3. 在ES6的箭头函数中,this指向创建者,并非调用者。

4. 通过call、apply、bind可以改变this的指向。

首次撰写此类技术总结,难免忐忑,担心内容准确性或读者反馈。如有不足之处,欢迎指正。

以上是对JavaScript中this指向问题的总结,希望对大家有所帮助。如有任何疑问,欢迎留言,我会及时回复。

作者最新文章