this是JS的关键字,随着函数使用场合的不同,this值会发生变化。但总的原则是,this总是指向调用this所在函数的那个对象。
1、纯函数调用
function test(){ this.x=1; alert(x); } test();
这里的this就是全局变量。看下面的例子就能很好的理解this就是全局对象Global。
var x=1; function test(){ alert(this.x); } test(); //1 var x=1; function test(){ this.x=0; } test(); alert(x); //0
在JavaScript的变量作用域中规定,“全局变量都是window对象的属性。”因此执行test()时相当于window.test(),此时test函数体内的this关键字的指向变成了window对象。即将window对象的x变为0。
var x=1; var b={ x:2, getX:function(){ return this.x; } }; alert(this.x); //1 alert(b.getX()); //2
在上面的代码中,alert(this.x)中this指向window,所以在全局中搜寻x的值,为1;
alert(b.getX())中由于x所在函数作为对象b的方法被调用,this指向了b,因此在b中搜寻x的值,为2。
2、作为方法调用,那么this指调用方法的这个对象。
function test(){ alert(this.x); } var o={}; o.x=1; o.m=test; o.m(); //1
3、作为构造函数调用。此时this指向新生成的对象。
function Test(){ this.x=1; } var o= new Test(); alert(o.x); //1
4、apply调用。this指向的是apply中的第一个参数。
var x=0; function test(){ alert(this.x); } var 0={}; o.x=1; o.m=test(); o.m.apply(); //0 o.m.apply(o);//1
当apply没有参数时,表示为全局对象。所以值为0。
5、箭头函数中的this
箭头函数要实现类似纯函数的效果,必须剔除外部状态。所以当你定义一个箭头函数时,在普通函数里常见的this、arguments、caller都是没有的。
箭头函数里没有this。如下代码里可以取到this。这是为什么呢?
function foo(){ let a=1; let b=()=>console.log(this.a); b(); } foo(); //1
以上箭头函数中的this实际上是父级作用域中的this,即函数foo的this。箭头函数引用了父级的变量,构成一个闭包。以上代码等价于:
function foo(){ let a=1; let self=this; let b=()=>console.log(selt.a); b(); } foo(); //1
箭头函数不仅没有this,常用的arguments也没有。如果你能获取到arguments,那它一定是来自父作用域的。
function foo(){ return ()=>console.log(arguments[0]); } foo(1,2)(3,4); //1
上例中如果箭头函数有arguments,就应该输出的是3而不是1。
一个经常犯的错误是使用箭头函数定义对象的方法,如:
let a ={ foo:1, bar:()=>console.log(this.foo) }; a.bar(); //undefined
以上代码中,箭头函数中的this并不是指向a这个对象。对象a并不能构成一个作用域,所以再往上到达全局作用域,this就指向全局作用域。如果我们使用普通函数的定义方法,输出结果就符合预期,这是因为a.bar()函数执行时作用域绑定到了a对象。
let a ={ foo:1, bar:function(){console.log(this.foo)} }; a.bar(); //1
另一个错误是在原型上使用箭头函数。如:
function A(){ this.foo=1; } A.prototype.bar=()=>console.log(this.foo); let a=new A; a.bar(); //undefined
同样,箭头函数中的this不是指向A,而是根据变量查找规则回溯到了全局作用域。同样,使用普通函数就不存在问题。在什么情况下使用箭头函数:
A、箭头函数适合于无复杂逻辑或者无副作用的纯函数场景下。例如用在map、reduce、filter的回调函数定义中;
B、不要在最外层定义箭头函数,因为在函数内部操作this会很容易污染全局作用域。最起码在箭头函数外部包一层普通函数,将this控制在可见的范围内;
C、箭头函数最大的好处是简洁。在有多层函数嵌套的情况下,箭头函数的间接性并没有提升,反而影响了函数的作用范围的识别度,这种情况不建议使用箭头函数。