创见博客
this(上下文对象)常见考题
七崽爱吃小饼干2026/01/21阅读 2专栏 JavaScript

一、基础题(考察核心绑定规则)

题1:默认绑定 vs 隐式绑定

javascript
var name = '全局';
const obj = {
  name: '对象',
  sayName: function() {
    console.log(this.name);
  }
};

obj.sayName(); // 输出?
const fn = obj.sayName;
fn(); // 输出?

分析:

  • obj.sayName():函数作为 obj 的方法调用,触发隐式绑定,this 指向 obj;
  • fn():把 obj.sayName 赋值给 fn 后,fn 是独立调用,触发默认绑定,this 指向全局对象(浏览器中 window)。

答案:

对象
全局

题2:显式绑定(call/apply/bind)

javascript
function fn(a, b) {
  console.log(this.x, a + b);
}
const obj = { x: 10 };

fn.call(obj, 1, 2); // 输出?
fn.apply(obj, [3, 4]); // 输出?
const bindFn = fn.bind(obj, 5, 6);
bindFn(); // 输出?

分析:

  • call:立即执行,this 绑定 obj,参数逐个传递;
  • apply:立即执行,this 绑定 obj,参数以数组传递;
  • bind:返回新函数,this 永久绑定 obj,参数提前预设(柯里化)。

答案:

10 3
10 7
10 11

题3:new 绑定

javascript
function Person(name) {
  this.name = name;
  this.say = function() {
    console.log(this.name);
  };
}

const p1 = new Person('小明');
p1.say(); // 输出?

const p2 = new Person('小红');
p2.say(); // 输出?

分析: new 调用构造函数时,this 指向新创建的实例对象,每个实例的 this 独立。

答案:

小明
小红

二、进阶题(考察规则优先级/特殊场景)

题1:绑定规则优先级(new > bind > 隐式)

javascript
const obj = {
  x: 1,
  fn: function() {
    console.log(this.x);
  }
};
const obj2 = { x: 2 };

// 先 bind 绑定 obj2,再用 new 调用
const bindFn = obj.fn.bind(obj2);
new bindFn(); // 输出?

分析: new 绑定的优先级 > 显式绑定(bind),因此 this 指向 new 创建的空实例(无 x 属性)。

答案:

undefined

题2:箭头函数的 this

javascript
const obj = {
  x: 10,
  fn1: () => {
    console.log(this.x);
  },
  fn2: function() {
    const fn3 = () => {
      console.log(this.x);
    };
    fn3();
  }
};

obj.fn1(); // 输出?
obj.fn2(); // 输出?
obj.fn1.call({ x: 20 }); // 输出?

分析:

  • obj.fn1():箭头函数无自己的 this,继承外层全局作用域的 this(浏览器中 window.x 不存在);
  • obj.fn2():fn3 是箭头函数,继承 fn2 的 this(fn2 由 obj 调用,this 指向 obj);
  • obj.fn1.call(...):箭头函数的 this 无法被 call/apply/bind 修改,依然指向全局。

答案:

undefined
10
undefined

题3:嵌套函数 + this 丢失

javascript
var x = '全局';
const obj = {
  x: '对象',
  fn: function() {
    function innerFn() {
      console.log(this.x);
    }
    innerFn();
  }
};

obj.fn(); // 输出?

// 改造:让 innerFn 输出 '对象',有几种方法?

分析: innerFn 是独立调用,触发默认绑定,this 指向全局。

答案:

全局

改造方法:

javascript
// 方法1:保存外层 this
const obj = {
  x: '对象',
  fn: function() {
    const that = this; // 保存 obj 的 this
    function innerFn() {
      console.log(that.x); // 输出:对象
    }
    innerFn();
  }
};

// 方法2:箭头函数
const obj = {
  x: '对象',
  fn: function() {
    const innerFn = () => {
      console.log(this.x); // 继承 fn 的 this(指向 obj),输出:对象
    };
    innerFn();
  }
};

// 方法3:显式绑定
const obj = {
  x: '对象',
  fn: function() {
    function innerFn() {
      console.log(this.x);
    }
    innerFn.call(this); // 绑定 fn 的 this,输出:对象
  }
};

题4:DOM 事件中的 this

html
<button id="btn">按钮</button>
<script>
const btn = document.getElementById('btn');
btn.x = 100;
btn.onclick = function() {
  console.log(this.x); // 输出?
  
  setTimeout(function() {
    console.log(this.x); // 输出?
  }, 0);
  
  setTimeout(() => {
    console.log(this.x); // 输出?
  }, 0);
};
</script>

分析:

  • 事件处理函数中,this 指向触发事件的 DOM 元素(btn);
  • 第一个 setTimeout 回调:独立调用,this 指向全局(无 x);
  • 第二个 setTimeout 回调:箭头函数,继承外层事件处理函数的 this(指向 btn)。

答案:

100
undefined
100

三、高频面试思考题

  1. 为什么要使用 this? 答:避免硬编码,让函数可以复用(比如同一个函数能被不同对象调用,指向不同的上下文),提升代码灵活性。
  2. 箭头函数和普通函数的 this 有什么区别? 答:① 箭头函数无自己的 this,继承外层作用域的 this;② 箭头函数的 this 无法被 call/apply/bind 修改;③ 箭头函数不能作为构造函数(new 调用会报错)。
  3. 如何永久改变一个函数的 this 指向? 答:使用 bind 方法(call/apply 是临时改变,调用后恢复;bind 返回新函数,this 永久绑定)。

总结

  1. 解决 this 指向问题的核心:判断函数的调用方式,按优先级(new > 显式 > 隐式 > 默认)确定 this 指向;
  2. 箭头函数是特例:无自身 this,继承外层作用域,且无法修改;
  3. 嵌套函数/回调函数易丢失 this,可通过「保存外层 this」「箭头函数」「显式绑定」解决。
评论
0/100