注意:谁调用它,this就指向谁
全局执行
- 浏览器
console.log(this);
// Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage, sessionStorage: Storage, webkitStorageInfo: DeprecatedStorageInfo…}
打印出来了window
对象。
- Node
console.log(this);
// global
- 总结:在全局作用域中它的
this
执行当前的全局对象(浏览器端是Window
,node 中是global
)。
函数执行
- 纯粹的函数调用
最普通的函数使用方法:
function test() {
console.log(this);
};
test();
// Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage, sessionStorage: Storage, webkitStorageInfo: DeprecatedStorageInfo…}
我们可以看到,一个函数被直接调用的时候,属于全局调用,这时候它的 this
指向 全局对象;
- 严格模式: 'use strict'
如果在严格模式的情况下执行纯粹的函数调用,那么这里的的this
并不会指向全局,而是undefined
,这样的做法是为了消除 js 中一些不严谨的行为:
use strict';
function test() {
console.log(this);
};
test();
// undefined
当然,把它放在一个立即执行函数中会更好,避免了污染全局:
(function (){
"use strict";
console.log(this);
})();
// undefined
作为对象的方法调用
当一个函数被当作一个对象的方法调用的时候:
var obj = {
name: 'qiutc',
foo: function() {
console.log(this.name);
}
}
obj.foo();
// 'qiutc'
这时候,this
指向当前的这个对象;
如果把对象的方法赋值给一个变量,然后直接调用这个变量呢:
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
}
}
var test = obj.foo;
test();
// Window
可以看到,这时候 this
执行了全局,当我们把 test = obj.foo
,text
直接把等号右边当做一个函数,并不管什么obj
。test
直接指向了一个函数的引用,这时候,其实和 obj
这个对象没有关系了,所以,它是被当作一个普通函数来直接调用,因此,this
指向全局对象。重点。
经典例子
var obj = {
name: 'qiutc',
foo: function() {
console.log(this); //直接打印出obj整个对象
},
foo2: function() {
console.log(this); //打印出整个obj对象
var _this = this;
setTimeout(function() {
console.log(this); // Window
console.log(_this); // Object {name: "qiutc"}
}, 1000);
}
}
obj.foo2();
obj.foo();
- 首先,因为
谁调用this,this就指向谁
,所以,foo和foo2里面的console.log(this)
直接指向调用他们的obj对象,打印出Obj整个对象。 - 然后,在看
setTimeout
里面的。在外面,var _this = this;
这个this
是指向obj的(上面已经打印出来了)。用一个变量_this
来储存。所以console.log(_this);
可以打印出obj对象。因为我们已经用_this来指向obj对象了,所以console.log(this); // Window
。this只能指向全局了。 - 还有一点就是在foo2作用域内非setTimeout作用域内
console.log(this);
发现打印出obj对象。console.log(_this);
也是这样。说明setTimeout
块级作用域隔绝了foo2
作用域的渗透。
作为一个构造函数使用
在 js 中,为了实现类,我们需要定义一些构造函数,在调用一个构造函数的时候需要加上 new
这个关键字:
function Person(name) {
this.name = name;
console.log(this);
}
var p = new Person('qiutc');
// Person {name: "qiutc"}
我们可以看到当作构造函数调用时,this
指向了这个构造函数调用时候实例化出来的对象;
当然,构造函数其实也是一个函数,如果我们把它当作一个普通函数执行,这个 this
仍然执行全局:
function Person(name) {
this.name = name;
console.log(this);
}
var p = Person('qiutc');
// Window
其区别在于,如何调用函数(new
)
箭头函数
在 ES6 的新规范中,加入了箭头函数,它和普通函数最不一样的一点就是 this
的指向了。用闭包来解决 this
的指向问题,用上了箭头函数就可以更完美的解决。
var obj = {
name: 'qiutc',
foo: function() {
console.log(this);
},
foo2: function() {
console.log(this);
setTimeout(() => {
console.log(this); // Object {name: "qiutc"}
}, 1000);
}
}
obj.foo2();
可以看到,在 setTimeout
执行的函数中,本应该打印出在 Window
,但是在这里 this
却指向了 obj
,原因就在于,给 setTimeout
传入的函数(参数)是一个箭头函数:
箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
根据例子我们理解一下这句话:
在 obj.foo2()
执行的时候,当前的 this
指向 obj
;在执行 setTimeout
时候,我们先是定义了一个匿名的箭头函数,关键点就在这,箭头函数内的 this
执行定义时所在的对象,就是指向定义这个箭头函数时作用域内的 this
,也就是 obj.foo2
中的 this
,即 obj
;所以在执行箭头函数的时候,它的 this
-> obj.foo2 中的 this
-> obj
;
简单来说, 箭头函数中的 this 只和定义它时候的作用域的 this 有关,而与在哪里以及如何调用它无关,同时它的 this 指向是不可改变的。这个箭头函数在foo2
的作用域下,所以就指向foo2
。
所以对于箭头函数,只要看它在哪里创建的就行。
网友评论