彻底搞懂this的几种场景,以及常见的错题和面试题
本文整合JS中this关键字的核心知识点、记忆口诀、易错点复盘,以及bind/call/apply三大方法的用法,结合经典面试题和个人错题,适合整理成博客存档,助力面试备考,彻底吃透this指向问题。 核心总纲:this不看书写时,只看运行时;谁调用,指向谁(箭头函数除外) 优先级口诀(从高到低):new绑定 \> bind硬绑定 \> 对象方法隐式绑定 \> 普通调用默认绑定 \> 箭头函数继承绑定 三者核心作用:手动改变函数的this指向,区别在于调用方式、传参形式和是否永久绑定。 以下是之前做题时出错的题目,重点分析错误原因,对应this核心规则,彻底避免再错。 误以为“obj调用foo,this就指向obj”,忽略了箭头函数无自身this,且对象{}不产生作用域。 忘记bind的“永久绑定”特性,误以为fn()是普通调用,this会变回window。 和第7题错误一致,混淆了“对象调用”和“箭头函数的this继承规则”,忽略对象不产生作用域。 能选对答案,但未彻底掌握“普通函数vs箭头函数”在异步回调中的this区别。 以下题目覆盖所有核心场景,结合前面的知识点,可自行先做题,再看解析巩固。 解析:普通函数直接调用,无明确调用者,this指向全局window(浏览器),window.a=10。 解析:obj调用foo,谁调用this指向谁,this=obj,obj.a=20。 解析:fn接收的是foo函数本身,并非obj调用;fn()是普通直接调用,this指向全局。 解析:new调用构造函数,this指向新创建的实例对象(f),函数内部this.a=30,打印实例。 解析:setTimeout回调是普通函数,由window调用,this=window,window.a=10。 解析:箭头函数无自身this,继承外层foo的this(foo被obj调用,this=obj),obj.a=10。 解析:箭头函数无自身this,外层无普通函数,this=window,window.a=100(对象不产生作用域)。 解析:call临时将foo的this绑定到obj2,立即执行,this=obj2,obj2.a=2。 解析:bind生成新函数fn,this永久绑定obj,fn()调用时,this=obj,obj.a=20。 解析: this的核心难点在于“运行时绑定”和“箭头函数的继承规则”,记住口诀+分清场景,就能避开90%的坑: 收藏本文,面试前快速过一遍口诀和错题,就能轻松应对this相关面试题~JS中this关键字详解(面试必背+错题复盘+bind/call/apply用法)
一、this核心记忆口诀(背会直接破题)
二、bind、call、apply 用法详解(重点区分)
1. call 方法
函数名\.call\(指定的this, 参数1, 参数2, \.\.\.\)function foo(a, b) {
console.log(this.name, a + b);
}
const obj = { name: "张三" };
foo.call(obj, 1, 2); // 输出:张三 3(this临时指向obj,立即执行)
foo(); // 输出:undefined/global (this恢复默认,绑定失效)
2. apply 方法
函数名\.apply\(指定的this, \[参数1, 参数2, \.\.\.\]\)function foo(a, b) {
console.log(this.name, a + b);
}
const obj = { name: "李四" };
foo.apply(obj, [1, 2]); // 输出:李四 3(参数是数组,其余和call一致)
foo(); // 绑定失效,this恢复默认
3. bind 方法
const 新函数 = 原函数\.bind\(指定的this, 参数1, 参数2, \.\.\.\)function foo(a, b) {
console.log(this.name, a + b);
}
const obj = { name: "王五" };
const newFoo = foo.bind(obj, 1, 2); // 生成新函数,this永久绑定obj
newFoo(); // 输出:王五 3
newFoo.call({ name: "赵六" }); // 依然输出:王五 3(绑定不可改)
4. 三者对比表
方法 是否立即执行 this绑定特性 参数传递方式 核心特点 call 是 临时绑定,仅当前生效 列表形式(逗号分隔) 临时借用this,单次使用 apply 是 临时绑定,仅当前生效 数组形式 参数较多时更便捷 bind 否 永久绑定,生成新函数 列表形式(可预传参) 可重复使用,绑定不可改 三、个人错题复盘(箭头函数+bind易错重点)
错题1:对象中的箭头函数(第7题)
var a = 100;
var obj = {
a: 200,
foo: () => {
console.log(this.a);
}
};
obj.foo(); // 我的答案:200 → 正确答案:100
错误原因
正确解析
错题2:bind永久绑定(第9题)
var a = 10;
function foo() {
console.log(this.a);
}
var obj = { a: 20 };
var fn = foo.bind(obj);
fn(); // 我的答案:window → 正确答案:20
错误原因
正确解析
错题3:对象中箭头函数的this(第10题fn2)
var name = 'global';
var obj = {
name: 'obj',
fn1: function() { console.log(this.name) },
fn2: () => { console.log(this.name) },
};
obj.fn2(); // 我的答案:obj → 正确答案:global
错误原因
正确解析
错题4:setTimeout中箭头函数与普通函数(第5、6题对比)
// 第5题(普通函数)
var obj = {
a: 10,
foo: function() {
setTimeout(function() {
console.log(this.a); // 我的答案:window(正确),但理解不透彻
}, 100);
}
};
obj.foo();
// 第6题(箭头函数)
var obj = {
a: 10,
foo: function() {
setTimeout(() => {
console.log(this.a); // 我的答案:obj(正确),但分不清和第5题的区别
}, 100);
}
};
obj.foo();
错误原因
正确解析
四、this经典易错面试题(10道,含解析)
第1题:普通函数直接调用
var a = 10;
function foo() {
console.log(this.a);
}
foo(); // 答案:10(浏览器)/ undefined(严格模式)
第2题:对象方法调用
var obj = {
a: 20,
foo: function() {
console.log(this.a);
}
};
obj.foo(); // 答案:20
第3题:对象方法单独调用
var obj = {
a: 20,
foo: function() {
console.log(this.a);
}
};
var fn = obj.foo;
fn(); // 答案:10(浏览器)/ undefined(严格模式)
第4题:new构造函数调用
function Foo() {
this.a = 30;
console.log(this);
}
var f = new Foo(); // 答案:Foo { a: 30 }
第5题:setTimeout普通函数回调
var obj = {
a: 10,
foo: function() {
setTimeout(function() {
console.log(this.a);
}, 100);
}
};
obj.foo(); // 答案:10(浏览器)/ undefined(严格模式)
第6题:setTimeout箭头函数回调
var obj = {
a: 10,
foo: function() {
setTimeout(() => {
console.log(this.a);
}, 100);
}
};
obj.foo(); // 答案:10
第7题:对象中的箭头函数
var a = 100;
var obj = {
a: 200,
foo: () => {
console.log(this.a);
}
};
obj.foo(); // 答案:100
第8题:call临时绑定
var obj1 = {
a: 1,
foo: function() {
console.log(this.a);
}
};
var obj2 = {
a: 2,
};
obj1.foo.call(obj2); // 答案:2
第9题:bind永久绑定
var a = 10;
function foo() {
console.log(this.a);
}
var obj = { a: 20 };
var fn = foo.bind(obj);
fn(); // 答案:20
第10题:综合题(箭头+普通函数+对象调用)
var name = 'global';
var obj = {
name: 'obj',
fn1: function() {
console.log(this.name);
},
fn2: () => {
console.log(this.name);
},
};
obj.fn1(); // 答案:obj
var fn = obj.fn1;
fn(); // 答案:global
obj.fn2(); // 答案:global
五、总结
(注:文档部分内容可能由 AI 生成)