大多数的this指向我还是能辨别,但是偶尔遇到特殊的情况我还是会懵圈儿,所以整理整理。
首先,最为常见的this
,全局情况下(与严格非严格模式无关):
// 浏览器中的this
console.log(this); // 输出window对象
// 在NodeJS中的this对象
console.log(this); // 输出一个空对象:{}
在函数中,this
的指向又有些不同:
function test() {
console.log(this);
}
// 在浏览器中 宽松模式下输出window对象, 严格模式下输出undefined
// 在NodeJS中 宽松模式下输出global对象,在严格('use strict')模式下输出undefined
其实无论是nodejs中还是JavaScript中,函数的this指向的都是全局对象,主要区别在于这个函数在执行作用域中是否是严格模式非严格模式,换句话说就是是谁执行了test() 函数,是严格模式要是非严格模式
在对象的方法中, this
指向:
var obj = {
name: 'zhangsan',
fun: function () {
console.log(this.name);
}
}
obj.fun(); // 输出 'zhangsan'
var test = obj.fun; // 得到fun函数
test(); // 输出window对象
上例中的第一个this
指向的是当前obj这个对象。
第二个this
指向的全局对象;通过obj.fun
获得单独的函数,而此时的函数已经独立在obj
之外了,最后调用test()
相当于就是直接调用fun()函数,所以this
的指向就变成了window
对象。
回调函数中的this
以上的这些this
都是比较常见,比较容易的,但是遇到稍微复杂的回调函数,就容易掉入坑:
var obj = {
name: 'zhangsan',
foo: function () {
console.log(this);
},
foo2: function () {
console.log(this);
setTimeout(this.foo, 1000);
},
}
obj.foo2();
输出的结果为:
发现输出两个不同的结果,第一次输出的是foo2中的this
, 这个this
就指向的obj
这个对象,第二个this
却是指向的全局对象,这是为什么呢?
其实setTimeout 也是一个函数,我们需要给它传入参数,这里把this.foo
当做一个参数传入,实际上就做了这样的操作func = this.foo
, 直接把func指向了this.foo
的引用,在执行的之后this.foo
就与obj
这个对象无关了,相当于直接调用了一个普通的函数,因此this
就指向了全局对象。
我们可以使用闭包的方式来解决这个坑:
var obj = {
name: 'zhangsan',
foo: function () {
console.log(this);
},
foo2: function () {
console.log(this);
var _this = this;
setTimeout(function () {
console.log(this); // window对象
console.log(_this); // obj对象
}, 1000);
}
}
obj.foo2(); /
输出结果:
在构造函数中使用this
在JavaScript中,为了实现类,需要定义一些构造函数。
function Person(name){
this.name = name;
console.log(this);
}
var p = new Person('zhangsan'); // Person {name: 'zhangsan' }
调用这个构造函数时,this
指向了这个构造函数调用时候实例化出来的对象。
构造函数其实也是一个函数,如果我们把他当做一个普通函数, this
仍然指向window对象。
function Person(name) {
this.name = name;
console.log(this);
}
var p = Person('zhangsan'); // window
这两者区别就在于一个new
字
ES6规范中的箭头函数
在ES6中新增加了箭头函数,他和普通函数有点不一样,区别在于this
的指向问题。
var obj = {
name: 'zhangsan',
foo: function () {
console.log(this);
},
foo2: function () {
console.log(this);
setTimeout(()=> {
console.log(this); // 输出 obj 对象
}, 1000);
}
};
obj.foo2();
在前面 setTimeout()
回调函数中的this指向的是window,而在这里指的就是obj
对象,就是因为setTimeout()
函数传入的函数是一个箭头函数。
函数体内的this对象,就是定义所在的对象,而不是使用时所在的对象
简单说箭头函数中的this
纸盒定义它时候的作用域的this
有关,而与它在哪里以及符合调用它无关,同时它的this指向是不可改变的。
call, apply, bind
在JavaScript中,函数也是对象,使用call
, apply
, bind
更改this的指向
//call
function call(thisArg[, arg1[, ...]])
第一个参数是指定执行函数this
的上下文,后面的参数是执行函数需要传入的参数。
// apply
function apply(thisArg[, arg1,arg2, arg3,...])
第一个参数是指定执行函数中this
上下文,第二个参数是一个数组,传给执行函数的参数
//bind
var foo = func.bind(thisArg[, arg1[, arg2[, ...]]])
他不会执行函数,而是返回一个新的函数,这个新的函数被指定了this 上下文,后面的参数是执行函数需要传入的参数。
例子:
var obj = {
name: 'zhangsan'
}
function foo() {
console.log(this);
}
foo.call(obj); // {name: 'zhangsan'}
var obj = {
name: 'zhangsan',
foo: function () {
console.log(this);
}
}
var obj2 = {
name: '123455',
};
obj.foo.call(obj2); // {name: '123455'}