这次分享将简单的解释下JavaScript中的this的指向问题
大家在学习和使用JavaScript的过程中,不可避免的总会碰到函数中this的指向的问题。在网上的说法中,最常见的就是:说调用它,this就指向谁。那我们下面将会分析下全局中和函数中的this的指向。
首先,我们应该先知道 this的指向,是在函数调用的时候确定的 这样子的一个结论,一个函数的不同调用方式也会导致this指向不同的对象。下面有两个例子:
var a = 10;
var obj = {
a: 20
}
function getA(){
console.log(this.a);
}
getA();//10
getA.call(obj);//20
JavaScript内部提供了一种机制,让我们可以自行手动设置this的指向。它们就是call与apply。所有的函数都具有着两个方法。它们除了参数略有不同,其功能完全一样。它们的第一个参数都为this将要指向的对象。
就像上面的例子所示。getA并非属于对象obj的方法,但是通过call,我们将getA内部的this绑定为obj,因此就可以使用this.a访问obj的a属性了。这就是call/apply的用法。
除了call跟apply之外,JavaScript中还有一个bind方法,这个方法同样也还是用来手动设置this的指向,只不过跟call还有apply的最直观的区别就是,bind是返回一个函数:
var a = 10;
var obj = {
a: 20
}
function getA(){
console.log(this.a);
}
getA();//10
var get = getA.bind(obj);
get();//20
//或者是这样
getA.bind(obj)();//20
1.全局中的this
全局中的this也就是指向全局环境,也就是我们web中的window对象,对于JavaScript不在浏览器端的话,全局环境就是其顶部环境,像在node中的就是global对象。
var a1 = 10;
this.a2 = 20;
a3 = 30;
console.log(a1);//10
console.log(a2);//20
console.log(a3);//30
2.函数中的this
我们可以先看下下面两个例子:
var a = 20;
function fn(){
console.log(this.a);
}
fn();
demo2
var a = 20;
var obj = {
a: 10,
c: this.a+20,
fn: function(){
return this.a;
}
}
console.log(obj.c);
console.log(obj.fn());
但是我们需要特别注意的是demo2。在demo2中,对象obj中的c属性使用this.a + 20
来计算。这里我们需要明确的一点是,单独的{}
是不会形成新的作用域的,因此这里的this.a
,由于并没有作用域的限制,所以它仍然处于全局作用域之中。所以这里的this其实是指向的window对象。
在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。如果函数独立调用,那么该函数内部的this,则指向undefined。但是在非严格模式中,当this指向undefined时,它会被自动指向全局对象。
// 为了能够准确判断,我们在函数内部使用严格模式,因为非严格模式会自动指向全局
function fn() {
'use strict';
console.log(this);
}
fn(); // fn是调用者,独立调用
window.fn(); // fn是调用者,被window所拥有
var a = 20;
var foo = {
a: 10,
getA: function () {
return this.a;
}
}
console.log(foo.getA()); // 10
var test = foo.getA;
console.log(test()); // 20
foo.getA()中,getA是调用者,他不是独立调用,被对象foo所拥有,因此它的this指向了foo。而test()作为调用者,尽管他与foo.getA的引用相同,但是它是独立调用的,因此this指向undefined,在非严格模式,自动转向全局window。
function foo() {
console.log(this.a)
}
function active(fn) {
fn(); // 真实调用者,为独立调用
}
function getObj(obj){
obj.getA();
}
function activeBind(fn){
fn.bind(obj)();
}
var a = 20;
var obj = {
a: 10,
getA: foo
}
active(obj.getA);
getObj(obj);
activeBind(obj.getA);