首先需要明确的是函数中写的this只有在调用的时候,我们才能确定它的值是怎样的。因为函数调用时会生成一个新的执行上下文环境。
作为普通函数或全局函数调用
在全局作用域下,调用普通函数,浏览器端其this指向window。node中指向global。
var n = 'hello world !';
function example(){
this.n = 0;
}
console.log(n); // 0 !
另外需要注意一点,在严格模式下,未指定环境对象而调用函数,this的值是undefined。
作为构造函数调用
若直接调用该构造函数,与普通函数无区别,上面已经讲述。若是使用它创建对象,那么其中的this值会指向该新对象。
function Foo(){
this.x = 10;
console.log(this); //Foo {x:10}
}
var foo = new Foo();
console.log(foo.x); //10
作为对象的方法调用
如果函数作为对象的方法时,方法中的 this 指向该对象。
var obj = {
x: 10,
foo: function () {
console.log(this); //Object
console.log(this.x); //10
}
};
obj.foo();
若是不作为对象方法调用结果会是window。
var obj = {
x: 10,
foo: function () {
console.log(this); //Window
console.log(this.x); //undefined
}
};
var fn = obj.foo;
fn();
还有一种情况需要注意:
var obj = {
x: 10,
foo: function () {
function f(){
console.log(this); //Window
console.log(this.x); //undefined
}
f();
}
}
obj.foo();
函数 f 虽然是在 obj.foo 内部定义的,但它仍然属于一个普通函数,this 仍指向 window。
在这里,如果想要调用上层作用域中的变量 obj.x,可以使用缓存外部 this 变量的方法。
var obj = {
x: 10,
foo: function () {
var self = this;
function f(){
console.log(self); //{x: 10}
console.log(self.x); //10
}
f();
}
}
obj.foo();
构造函数 prototype 属性
function Foo(){
this.x = 10;
}
Foo.prototype.getX = function () {
console.log(this); //Foo {x: 10, getX: function}
console.log(this.x); //10
}
var foo = new Foo();
foo.getX();
在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前对象的值。这点需要注意。
用call、apply、bind调用
当一个函数被call、apply和bind调用时,this的值就取传入的对象的值。
var obj = {
x: 10
}
function foo(){
console.log(this); //{x: 10}
console.log(this.x); //10
}
foo.call(obj);
有一点需要注意,就是若没有传入对象,即call或apply参数为空,此时默认为传入全局对象。
var obj = {
x: 10
}
var x = 9;
function foo(){
console.log(this); //window
console.log(this.x); //9
}
foo.call();
apply与call只是传入参数写法不同,不再举例。
举例说明一下bind,也是可以改变作用域的,只要将传入的对象绑定到函数上即可。注意一下其调用方式。
var obj = {
x: 10
}
function foo(){
console.log(this); //{x: 10}
console.log(this.x); //10
}
foo.bind(obj)();
箭头函数
它的this指向与普通函数有很大的不同。箭头函数内部的 this 是词法作用域,由上下文确定。简单说就是箭头函数中的 this 只和定义它时候的作用域的 this 有关,而与在哪里以及如何调用它无关,同时它的 this 指向是不可改变的。
var obj = {
x: 10,
foo: function() {
var fn = () => {
return () => {
return () => {
console.log(this); //Object {x: 10}
console.log(this.x); //10
}
}
}
fn()()();
}
}
obj.foo();
对于箭头函数还需要注意一点,就是它的this确定后不会改变。使用call、apply、bind也无法改变它的this,因此使用它们传入的第一个参数无效。但是后面添加的参数值还是有效的。