this指向

this指向的四中情况在javascript里面,this的指向可以归纳为以下四种情况。只要能牢记这四种情况,大部分情况下就已经够用了。

1.在全局代码或者普通的函数调用中,this指向全局对象,在浏览器里面既为window对象

1
console.log(this);
//输出window
function foo(){
console.log(this);
}
foo();
//输出window

在浏览器环境里运行上述代码,两处输出结果均为window对象。

2.通过call或apply方法调用函数,this指向方法调用的第一个参数。

1
var obj = {name:'test'};
function foo(){
    console.log(this);
}
foo.call(obj);
//输出obj
foo.apply(obj);
//输出obj

在浏览器环境里执行以上代码,输出结果均为对象obj。call和apply除了参数形式不一样外其他都一样,call采用逗号分割,apply采用数组。说到这里,顺便介绍一个小技巧。如何在不生成新数组的情况下实现两个数组的连接?请看下面的代码。

1
var arr1 = [1, 2 , 3],
    rr2 = [4, 5, 6];
Array.prototype.push.apply(arr1, arr2);
console.log(arr1);
//输出[1, 2, 3, 4, 5, 6]

执行上述代码后,输出结果为[1, 2, 3, 4, 5, 6]。这是一个非常实用的小技巧,由于apply第二个参数为数组形式,所以我们可以把push方法“借”过来,从而实现两个数组的连接。

3.调用对象的方法,this指向该对象。

1
var obj = {name:'test'};
function foo(){
    console.log(this);
}
obj.foo = foo;
obj.foo();
//输出obj

执行以上代码后,控制台输出为obj对象。这就是我们常说的“谁调用,指向谁”。

4.构造方法中的this,指向新构造的对象。

1
function C(){
    this.name = 'test';
    this.age = 18;
    console.log(this);
}
var c = new C();
//输出 c
console.log(c);
//输出 c

执行以上代码后,控制台输出均为c所指向的对象。当new操作符用于函数时,会创建一个新对象,并用this指向它。

thisArg和this是一一对应的。

1
function foo(){  'use strict';
    console.log(this);
}
foo();
//输出undefined

该示例输出的结果为undefined。
第二点是说如果thisArg为null或者undefined则this指向全局对象。

1
function foo(){
    console.log(this);
}
foo.call(null);
//输出window

该示例的输出结果为window。
第三点说如果thisArg为非对象类型,则会强制转型成对象类型
``dash
function foo(){
console.log(this);
}
var aa = 2;
console.log(aa);
//输出2
foo.call(aa);
//输出 Number

1

这里的输出结果分别为2和Number,它将基本类型转型成了对象包装类型。
第四点说明剩下的情况thisArg和this为一一对应的关系。
规范里面对this指向的描述还是比较明确的。只要你搞清楚thisArg怎么确定,thisArg和this的对应关系,那么你就能搞定所有this的情况了。
确保this的指向在实际使用this的过程中,遇到得最多得一个问题可能就是上下文丢失的问题了。因为javascript中的函数是可以作为参数传递的,那么其他对象在执行回调函数时就可能造成回调函数原来的上下文丢失,也就是this的指向改变了。

```dash
var C = function(){
    this.name = 'test';
    this.greet = function(){
    console.log('Hello,I am '+this.name+'!');
};
}
var obj = new C();
obj.greet();
//输出 Hello,I am test!
setTimeout(obj.greet, 1000);
//输出 Hello,I am !

可见第二条输出中this的值改变了,其实我们是希望this能够指向obj的。解决该问题的方法有两种。

1.bind方法。
bind方法通过闭包巧妙地实现了上下文的绑定,它实际上是将原方法包装成了一个新方法。一般的实现如下:

1
Function.prototype.bind = function(){
    var args = arguments,        
        thisArg = arguments[0],
        func = this;
    return function(){
        var arg = Array.prototype.slice.call(args, 1);
        Array.prototype.push.apply(args, arguments);
        return func.apply(thisArg, arg);
    }
}

前面的示例代码我们只需要加上bind,就能够得到我们希望的结果了。

1
setTimeout(obj.greet.bind(obj), 1000);//输出 Hello,I am test! ...

2.es6箭头函数。
es6里面提供了一个新的语法糖,箭头函数。箭头函数的this不再变幻莫测,它永远指向函数定义时的this值。

1
var C = function(){
    this.name = 'test';
    this.greet = ()=>{ c
    onsole.log('Hello,I am '+this.name+'!');
    };
}
var obj = new C();
obj.greet();
//输出 Hello,I am test!
setTimeout(obj.greet, 1000);
//输出 Hello,I am test!

我们将前面的示例该成箭头函数后,两处的输出结果一样了。this的值不再改变了