this 指向谁?
多数情况下,this 指向调用它所在方法的那个对象。
说得更通俗点,谁调的函数,this 就归谁。当调用方法没有明确对象时,this 就指向全局对象。在浏览器中,指向 window
;在 Node 中,指向 Global
。(严格模式下,指向 undefined
)
this 的指向是在调用时决定的,而不是在书写时决定的。
举个栗子:
var a = {
b: 1,
f: function() {
console.log(this.b)
}
}
var b = 2;
a.f() // 1
上面栗子调用函数f
的是a
,所以函数指向时this指向的就是a
变一下
var a = {
b: 1,
f: function() {
console.log(this.b)
}
}
var fn = a.f;
var b = 2;
fn() // 2
上面栗子a.f
已经赋值给了fn
,fn
执行时没有指定调用对象,即this指向全局对象调用
在变一下
var a = {
b: 1,
f: function() {
console.log(this.b)
}
}
var m = {
b: 3,
f: function() {
var fn = a.f;
fn();
}
}
var b = 2;
m.f() // 2
上面m.f
执行输出的还是2
。其实还是还是上面提到的:this 的指向是在调用时决定的 关键最终调用执行输出的还是fn
切没有指定调用对象,所以this还是指向的全局对象。
特殊情况
在三种特殊情境下,this 会 100% 指向 window:
- 立即执行函数(IIFE)
- setTimeout 中传入的函数
- setInterval 中传入的函数
其实这也是可以通过上面的解释来理解的,立即执行函数执行时没有明确的调用对象,还是全局对象,而setTimeout和setInterval同样如此在调用时是全局对象来调用的。
**注意:**上面上面说的三种特殊情况是指的在对应函数内直接使用this
比如:
(function(){
console.log(this.b) // 2
})()
var b = 2;
并不是像下面这样:
(function(){
var a = {
b: 1,
f: function() {
console.log(this.b)}
}
a.f() // 1
})()
var b = 2;
这样调用方其实跟立即执行函数没啥关系,a.f
调用对象是a
箭头函数
箭头函数是最特殊的,所以单独来讲:箭头函数的this指向是有书写时决定的而非调用时,即指向箭头函数定义时所在作用域的调用对象 记住就好。
var a = {
b:1,
f1: () => {
console.log(this.b)
},
f2: function() {
console.log(this.b)
}
}
var b = 2;
a.f1(); // 2
a.f2(); // 1
上述栗子a.f1
为箭头函数由于定义时是在全局作用域下,所以指向全局对象输出2
,a.f2
普通函数指向调用对象输出1
变一下:
function Fn() {
this.a = {
b: 1,
f1: () => {
console.log(this.b);
},
f2: function () {
console.log(this.b);
},
};
this.b = 2;
this.run = function () {
this.a.f1(); // 2
this.a.f2(); // 1
console.log(this); // fn
};
}
var b = 3;
const fn = new Fn();
fn.run();
上述栗子可以明显看下a.f1
为箭头函数由于定义时是在fn
的函数作用域下,所以指向了Fn
实例化的对象fn
,a.f2
普通函数指向调用对象a
输出1
备注:
浏览器环境全局作用域下var
声明的变量会被挂在window
上,而let
、const
不会,因为let
和const
引入了更严格的块级作用域规则。
node环境下即便使用var
声明的全局变量不会被挂载到全局对象上,这是因为 node的模块机制和作用域规则与浏览器环境有所不同。在node中,每个模块都有自己的作用域。当您使用var
在模块的顶层声明一个变量时,它实际上是模块作用域内的变量,而不是全局对象的属性。
例题
var length = 10
function fn(){
console.log(this.length)
}
var obj = {
length:5,
method:function(fn){
fn()
arguments[0]()
console.log(arguments,'arguments')
}
}
obj.method(fn)
obj.method(fn, 123)
答案:
10
1
args
10
2
args