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
三、高频面试思考题
- 为什么要使用
this? 答:避免硬编码,让函数可以复用(比如同一个函数能被不同对象调用,指向不同的上下文),提升代码灵活性。 - 箭头函数和普通函数的
this有什么区别? 答:① 箭头函数无自己的this,继承外层作用域的this;② 箭头函数的this无法被call/apply/bind修改;③ 箭头函数不能作为构造函数(new调用会报错)。 - 如何永久改变一个函数的
this指向? 答:使用bind方法(call/apply是临时改变,调用后恢复;bind返回新函数,this永久绑定)。
总结
- 解决
this指向问题的核心:判断函数的调用方式,按优先级(new > 显式 > 隐式 > 默认)确定this指向; - 箭头函数是特例:无自身
this,继承外层作用域,且无法修改; - 嵌套函数/回调函数易丢失
this,可通过「保存外层 this」「箭头函数」「显式绑定」解决。