ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

JavaScript——this指向问题详解

2026/9/25 9:04:45 拓冰建站 浏览量
JavaScript——this指向问题详解

一、非箭头函数this指向

排除箭头函数,其他情况下this指向遵循下面规则:

  • 在全局上下文中,this指向全局对象(通常是window对象)。

    需要注意的是:

    • 非严格环境下,全局下的this指向window, 而在严格环境下是undefined。
    • setTimeout等都是挂载在window下的,因此setTimeout中的this,不管怎么写都指向window
  • 在对象方法中,this指向调用该方法的对象。

  • 函数独立调用时,this指向window,独立调用可以理解为,它没有上级。

    可以思考一下如下代码:

    let obj = {a: function () {function b() {console.log(this);}b();},
    };
    

    输出的结果是window,因为b函数是没有上级的,不像a函数作为方法调用,它的上级是obj。

  • 立即执行函数【也就是定义后立即执行的匿名函数】的this指向window。

    可以思考一下如下代码:

    let obj = {a: (function () {console.log(this);})(),b: function c() {(function () {console.log(this);})();},
    };obj.a;
    obj.b();
    

    上面两个都输出window,因为都是执行函数,只不过a成了对象的属性,b成了对象的方法。

  • 在构造函数中,this指向新创建的实例对象。

    需要注意的是:

    • 如果是function的构造函数,不加new的话会当成方法使用而不是构造函数,因此加new指向新构造的实例,不加new指向调用该方法的对象。
  • 在事件处理函数中,this通常指向触发事件的DOM元素。

function f1() {console.log(this);
}
function f2() {"use strict";  // 严格模式console.log(this);
}
function f3() {this.name = "zhangsan";console.log(this); 
}
f1();  // window
f2();  // undefined
f3();  // window  当成方法调用了而不是构造函数
new f3();  // f3新构造的实例对象

二、箭头函数this指向

箭头函数是JavaScript中的一个特殊情况。它们不会创建自己的this上下文,而是继承外部函数的this。这使得箭头函数的this是静态的,不会随着调用方式而改变。

三、隐式绑定导致的this丢失

在某些特殊情况下会存在this丢失的问题,常见的就是将调用函数作为参数传递或者变量赋值给另外一个变量,此时this指向window。

下面看代码:

let obj = {a: function () {console.log(this);},
};let b = obj.a;
obj.a();
b();

这里obj.a()运行的this指向obj对象,而b()运行的this指向window,因此b变量导致this丢失。上面的代码就相当于:

let obj = {a: function () {console.log(this);},
};let b = function () {console.log(this);
};
obj.a();
b();

四、经典面试题

题1

var a = 'a'
let b = 'b'
function foo() {console.log(this.a)console.log(this.b)
}
foo()

此题先输出a再输出b,因此var将变量a提升至顶级,并挂载到了window上,而let``不存在变量提升,不会被挂载到window`上。

题2

const obj1 = {fn: function () {return this;},
};const obj2 = {fn: function () {return obj1.fn();},
};const obj3 = {fn: function () {var fn1 = obj1.fn;return fn1();},
};console.log(obj1.fn()); // obj1
console.log(obj2.fn()); // obj1
console.log(obj3.fn()); // window

此题第一个输出很简单,指向调用fn()的对象obj1,

第二个输出就等同于在obj2对象内调用obj1对象的fn,因此fn方法指向调用它的obj1,

第三个输出出现隐式绑定导致的this丢失,因此就相当于在obj3的fn方法的作用域内新建了一个fn1函数,再在此作用域内独立执行函数,因为是独立执行,所以输出window。

题3

const obj = {foo: () => {console.log(this);},
};obj.foo();

此题输出window,因此foo为箭头函数,因此this指向上一级的上下文this,即obj所在的上下文window。

题4

let obj = {say: function () {var f1 = () => {console.log(this);};f1();},pro: {getPro: () => {console.log(this);},getPro2: function () {console.log(this);},},
};
let o = obj.say;
o(); // window
obj.say(); // obj
obj.pro.getPro(); // window
obj.pro.getPro2(); // pro

第一个输出发生隐式绑定导致this丢失,又因为f1是箭头函数,所以它的this继承o()的this,因此输出window。

第二个输出由于f1是箭头函数,所以它的this继承say()的this,因此输出obj。

第三个暂时没理解

第四个对象。

题5

var a = 1;
a = 2;
window.a = 3;
function foo() {let a = 4;this.a = 5;setTimeout(function () {console.log(a);}, 10);setTimeout(function () {console.log(this);console.log(this.a);}, 20);setTimeout(function () {console.log(a);}, 30);setTimeout(function () {console.log(this.a);}, 40);
}
foo()

输出顺序是 4 5 4 5。

分步解析:

  1. 首先var a = 1在全局对window上挂载了a: 1
  2. a = 2重新赋值了window上的a属性
  3. window.a = 3同理
  4. 执行foo()这段代码,,这里没加new,所以把它当成函数执行,foo内的this指向window,所以执行this.a = 5后,window上的a被修改为5。

这样就很容易理解了,第一个输出没加this,因此输出局部变量a ,等于4,第二个输出加了this,因此输出window上的a,等于5,后面同理