this 概览
this 在 js 中是一个内置指针变量,通常指向当前函数的调用对象
当不存在显式调用者的情况一般默认指向全局对象 window
箭头函数的 this 指向该函数所在的作用域指向的对象
一、全局作用域内的 this 指向
在全局作用域下,this始终指向全局对象window,无论是否是严格模式!
console.log(this); // 输出 window
window.console.log(this); // 输出 window
在全局作用域下,当没有显式调用的函数隐式被 window 调用,由于 this 指向函数的直接调用者,此时 this 指向全局对象 window
二、函数作用域内的 this 指向
函数内的 this 指向分为两种:非严格模式和严格模式
// 非严格模式
(function fn() {
console.log(this); // 输出 window
}())
// 严格模式
(function fn() {
'use strict'
console.log(this); // 输出 undefined
}())
非严格模式下函数作用域内因找不到当前显式调用者则隐式绑定到全局对象 window
严格模式下函数作用域内找不到显式调用者时无法获取到外部对象,此时 this 为 undefined
三、对象作用域内的 this 指向
对象内部方法的this指向调用这些方法的对象,也就是谁调用就指向谁
对象作用域内的 this 指向也分两种情况:普通对象和嵌套对象
let a = {
fn: function () {
console.log(this);
},
b: {
fnf: function () {
console.log(this);
}
}
}
// 普通对象
a.fn(); // 输出对象 a
a['fn'](); // 输出对象 a
// 嵌套对象
a.b.fnf(); // 输出对象 b
a['b']['fnf'](); // 输出对象 b
可以看出,对象作用域内因为需要使用 . 或 [ ] 操作符访问对象内成员,因此具有显式调用的情况。此时,this 指向为直接调用的对象,若有嵌套情况,仍指向调用该函数的对象
特殊情况
当调用的函数返回值仍是个函数时,其内部 this 指向为 window,若开启严格模式,则为 undefined
let c = {
d: function () {
return function () {
console.log(this);
}
}
}
c.d()(); // 输出对象 window
let c = {
d: function () {
'use strict'
return function () {
console.log(this);
}
}
}
c.d()(); // 输出 undefined
'use strict' 放置位置不影响输出结果
此种情况是因为函数内部形成了闭包,导致对象 c 调用属性名为 d 的函数时返回的函数调用暴露在全局作用域内,此时由函数 d 返回的函数调用则遵循全局 this 指向原则
四、箭头函数的 this 指向
箭头函数的this指向函数作用域所用的对象
由于箭头函数不能绑定 this,因此严格意义上来说箭头函数没有自己的 this 指针,准确来说是没有指向的对象。其 this 指针在被定义时会捕获外层执行环境,并将自身的 this 指向外层 this,当完成初始化后便无法更改定义后的箭头函数的 this 指向,包括 call、apply、bind等方法
let a = {
fn: function () {
console.log(this);
return () => {
console.log(this);
}
},
b: {
fnf: () => {
console.log(this);
return () => {
console.log(this);
}
}
}
}
a.b.fn()(); // 输出对象 a
a.b.fnf()(); // 输出对象 window
第一个箭头函数其定义在 fn 这个函数内,而 fn 函数内的 this 指向对象 a,则箭头函数内的 this 最终指向对象 a。第二个箭头函数定义在另一个箭头函数内,由于箭头函数 this 指针会指向最外层对象,则通常为全局对象window
五、构造函数内的 this 指向
构造函数内的this指向为与构造函数同名的实例
function Fn(...args) {
console.log(this) // 输出 Fn {}
this.id = args[0];
this.userName = args[1];
this.password = args[args.length - 1];
console.log(this);
}
new Fn('000123', 'lily', '123456'); // 输出 Fn {id: '000123', userName: 'lil y', password: '123456'}
构造函数内this会指向即将返回的实例,从而我们得以使用this指针来初始化实例
六、原型链中的this
this在一个继承机制中,仍是指向它原本属于的对象,而不是从原型链上找到它时所属于的对象
let obj = {
fn: function () {
console.log(this);
}
}
let obj_extend = {
fnf: function () {
console.log(this);
}
};
obj_extend.__proto__ = obj;
console.log(obj_extend); // 输出对象 obj_extend
这个例子中,将 obj_extend 的原型修改为 obj,由此继承了 obj 上的 fn 方法,通过输出对象可以看出,此时 fn 函数原本指向 obj 的this指向了obj_extend。由于直接调用 fn 函数的是 obj_extend,且发生了赋值操作,this 绑定隐式丢失,因此fn函数内的this指向其直接调用者
七、总结
本文整理了常见情况下的 this 指向问题,介于问题的复杂性,考虑对主动修改this的方法,如:call、apply、bind方法暂未涉及,详情可参考 CSDN上其他博主的博客
理解this指向有助于更好的帮助我们在日常开发过程中更好的灵活使用,提高我们的开发效率。同时也间接提高了js编码水平,从这些方面来说,这个知识点的重要性还是比较高的