2016-12-29 js中this在不同环境的指向

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,
实际上this的最终指向的是那个调用它的对象

1.函数调用模式

当作函数调用,这时函数内的this指向全局对象(大对数情况下是window)

function a(){    
   var num= 233;    
   console.log(this.num); //undefined    
   console.log(this); //Window
}
a();
1
2
3
4
5
6

按照我们上面说的this最终指向的是调用它的对象,
这里的函数a实际是被Window对象所点出来的,
相当于window.a();
a() 是 一个函数也可以说是方法 ,那方法肯定是由对象来调用的。
所以当执行 a(); 时 就有一个隐式对象调用了a() ,这个隐式对象就是 window;

2.方法调用模式

当一个函数是一个对象的属性时,我们称它为该对象的一个方法,当一个方法被调用时,this指向该对象;

var o = {
    t:"test",
    fn:function(){
        console.log(this.t);  //test
    }
}
o.fn();
1
2
3
4
5
6
7

这里的this指向的是对象o,因为调用这个fn是通过o.fn()执行的,那自然指向就是对象o,
这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁;
如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象;

var o = {
    a:10,
    b:{        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();//尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,  
不管这个对象中有没有this要的东西  
还有一种比较特殊的情况:
1
2
3
4
5
6
7
8
9
10
11
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();
这里this指向的是window,this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的;  
虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

3.构造器调用模式 使用new调用的函数称为构造器函数,此时的this指向该构造器函数实例出来的对象;

function Fn(){    
    this.user = "test";
}
 var a = new Fn();
console.log(a.user); //test
1
2
3
4
5

这个this指向对象a,这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a;

这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行, 而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象Fn中会有user, 因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。   除了上面的这些以外,还可以自行改变this的指向,用JavaScript中call,apply,bind方法更改this的指向。    一个小问题当this碰到return时

function fn()  
{  
    this.user = 'test';  
    return {};  
}
var a = new fn;  
console.log(a.user); //undefined
1
2
3
4
5
6
7

再看一个

function fn()  
{  
    this.user = 'test';  
    return function(){};
}
var a = new fn;  
console.log(a.user); //undefined
1
2
3
4
5
6
7

再来

function fn()  
{  
    this.user = 'test';  
    return 1;
}
var a = new fn;  
console.log(a.user); //test

function fn()  
{  
    this.user = 'test';  
    return undefined;
}
var a = new fn;  
console.log(a.user); //test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

什么意思呢?   如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。

function fn()  
{  
    this.user = 'test';  
    return undefined;
}
var a = new fn;  
console.log(a); //fn {user: "test"}
1
2
3
4
5
6
7

还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。

function fn()  
{  
    this.user = 'test';  
    return null;
}
var a = new fn;  
console.log(a.user); //test
1
2
3
4
5
6
7

4.apply/call调用模式以及bind

apply、call、bind方法可以让我们设定调用者中的this指向谁

function showValue(){
  console.log(this.value);
}
var obj={
  value:4
}
showValue.call(obj)//输出4,this指向了obj对象
call():

var a = {
    user:"test",
    fn:function(){
        console.log(this.user); //test
    }
}
var b = a.fn;
b.call(a);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

通过在call方法,给第一个参数添加要把b添加到哪个环境中,简单来说,this就会指向那个对象,这里指向a ;
apply();
apply方法和call方法有些相似,它也可以改变this的指向;

var a = {
    user:"test",
    fn:function(){
        console.log(this.user); //test
    }
}
var b = a.fn;
b.apply(a);
//注意如果call和apply的第一个参数写的是null,那么this指向的是window对象
1
2
3
4
5
6
7
8
9

5.箭头函数中调用:

es6里面this指向固定化,始终指向外部对象,因为箭头函数没有this,因此它自身不能进行new实例化,
同时也不能使用call, apply, bind等方法来改变this的指向;

function Timer() {        
    this.seconds = 0;
    setInterval( () => this.seconds ++, 1000);
 } 
    var timer = new Timer();
    
 setTimeout( () => console.log(timer.seconds), 3100);    
    // 3
1
2
3
4
5
6
7
8

在构造函数内部的setInterval()内的回调函数, this始终指向实例化的对象, 并获取实例化对象的seconds的属性, 每1s这个属性的值都会增加1。 否则最后在3s后执行setTimeOut()函数执行后输出的是0;

6.Eval函数

该函数执行的时候,this绑定到当前作用域的对象上

    var name="XL";    
    var person={
        name:"xl",
        showName:function(){            
            eval("console.log(this.name)");
        }
    }
    
    person.showName();  //输出  "xl"
    
    var a=person.showName;
    a();  //输出  "XL"
1
2
3
4
5
6
7
8
9
10
11
12

##严格模式 ‘use strict’;

如果在严格模式的情况下执行纯粹的函数调用,那么这里的的
this 并不会指向全局,而是 undefined,这样的做法是为了消除 js 中一些不严谨的行为;

'use strict';
function test() {
  console.log(this);
};

test();

// undefined
1
2
3
4
5
6
7
8

部分参考:追梦子http://www.cnblogs.com/pssp/p/5216085.html

working study......