大家好啊!我是大华! 经常面试的朋友应该知道,JavaScript
中的this
指向是一个非常经典的问题。很多朋友一听到this
就头皮发麻。所以来整理了一下这篇文章。
先来个最简单粗暴的理解:this就是一个指向函数执行时所属对象的引用。就是:谁调用这个函数,this就指向谁。
我们看几个真实场景就明白了!
场景1:普通函数调用
javascript
function sayHello() {
console.log(this === window);
}
sayHello(); // 输出:true
这里直接调用sayHello
,相当于window.sayHello()
,所以this指向window。
但在严格模式下:
javascript
"use strict";
function sayHello() {
console.log(this);
}
sayHello(); // 输出:undefined
看,严格模式下this
就是undefined
,避免了指向全局对象的问题。
场景2:对象方法调用
javascript
const person = {
name: "小明",
sayName: function() {
console.log("我叫" + this.name);
}
};
person.sayName(); // 输出:我叫小明
这里sayName
是person
对象的方法,所以this指向person对象。
但是注意这个坑:
javascript
const person = {
name: "小明",
sayName: function() {
console.log("我叫" + this.name);
}
};
const say = person.sayName;
say(); // 输出:我叫undefined
为什么?因为say()
是直接调用的,this指向了window,而window没有name属性。
场景3:构造函数调用
javascript
function Person(name) {
this.name = name;
}
const xiaoming = new Person("小明");
console.log(xiaoming.name); // 输出:小明
使用new
操作符时,this
指向新创建的对象实例。
场景4:箭头函数
这是ES6的新特性,也是面试常考点:
javascript
const person = {
name: "小明",
hobbies: ["篮球", "游泳"],
showHobbies: function() {
this.hobbies.forEach(function(hobby) {
console.log(this.name + "喜欢" + hobby);
});
}
};
person.showHobbies();
// 输出:undefined喜欢篮球
// 输出:undefined喜欢游泳
为什么是undefined?因为forEach里的回调函数是独立调用的,this指向window。
用箭头函数解决:
javascript
const person = {
name: "小明",
hobbies: ["篮球", "游泳"],
showHobbies: function() {
this.hobbies.forEach((hobby) => {
console.log(this.name + "喜欢" + hobby);
});
}
};
person.showHobbies();
// 输出:小明喜欢篮球
// 输出:小明喜欢游泳
箭头函数的this继承自外层作用域,所以这里指向person对象。
场景5:改变this指向
有时候我们需要手动改变this指向,JavaScript提供了3个方法:
call方法:
javascript
function introduce(age, hobby) {
console.log(`我是${this.name},今年${age}岁,喜欢${hobby}`);
}
const person = { name: "小明" };
introduce.call(person, 18, "篮球");
// 输出:我是小明,今年18岁,喜欢篮球
apply方法:
javascript
function introduce(age, hobby) {
console.log(`我是${this.name},今年${age}岁,喜欢${hobby}`);
}
const person = { name: "小明" };
introduce.apply(person, [18, "篮球"]);
// 输出:我是小明,今年18岁,喜欢篮球
bind方法:
javascript
function introduce(age, hobby) {
console.log(`我是${this.name},今年${age}岁,喜欢${hobby}`);
}
const person = { name: "小明" };
const introduceXiaoming = introduce.bind(person, 18);
introduceXiaoming("游泳");
// 输出:我是小明,今年18岁,喜欢游泳
记住这个判断顺序,面试时超有用:
- 函数是否用
new
调用?是 →this
指向新对象 - 是否用
call/apply/bind
指定this
?是 → this指向指定对象 - 是否是箭头函数?是 →
this
继承外层作用域 - 是否是对象的方法?是 →
this
指向该对象 - 以上都不是 →
this
指向全局对象(严格模式下为undefined)
总结
this指向其实就一句话:看函数是怎么被调用的,而不是在哪里定义的。
记住几个关键点:
- 普通函数调用:指向全局对象(或undefined)
- 对象方法调用:指向该对象
- 构造函数调用:指向新创建的实例
- 箭头函数:继承外层作用域的this
- 可以用
call/apply/bind
手动改变this
指向
下次面试官再问this
,你就可以自信地回答了!记得多写代码多练习,实践出真知哦~
希望这篇文章对你有帮助!如果有任何问题,欢迎留言讨论~
📌往期精彩
《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》
《只会写 Mapper 就敢说会 MyBatis?面试官:原理都没懂》
《别再手写判空了!SpringBoot 自带的 20 个高效工具类》