this对象是在运行时基于函数的执行环境绑定的,在全局函数中,this等于window,而当函数被作为某个对象的方法调用时this等于调用的那个对象。

1.全局代码中的this

全局范围内的this将会指向全局对象,在浏览器中即使window。

2.作为单纯的函数调用

<table><tbody><tr><td></td><td>

function fooCoder(x) {

this.x = x;

fooCoder(2);

alert(x);// 全局变量x值为2

</td></tr></tbody></table>

这里this指向了全局对象,即window。在严格模式中,则是undefined。

3.作为对象的方法调用

<table><tbody><tr><td></td><td>

var name = "Window";

var person = {

name : "Person",

hello : function(sth){

console.log(this.name + " says " + sth);

person.hello("hello world");

</td></tr></tbody></table>

输出 Person says hello world。this指向person对象,即当前对象。

4.作为构造函数

函数内部的this指向新创建的对象。

5.匿名函数

<table><tbody><tr><td></td><td>

var name = "Window";

var person = {

name : "Person",

hello : function(sth){

var sayhello = function(sth) {

console.log(this.name + " says " + sth);

sayhello(sth);

person.hello("hello world");//Window says hello world

</td></tr></tbody></table>

匿名函数的执行环境具有全局性,因此其this对象通常指向window。为什么匿名函数没有取得其包含作用域(或外部作用域)的this对象呢?

其实,每个函数在被调用时都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个对象时,只会搜索到其活动对象为止,因此永远不可能访问到外部函数中的这两个变量。

为了解决这个问题,一般的处理方式是把外部作用域中的this作为变量保存在一个闭包能够访问的位置,如下:

<table><tbody><tr><td></td><td>

var name = "Window";

var person = {

name : "Person",

hello : function(sth){

<strong>var self=this;</strong>

var sayhello = function(sth) {

console.log(self.name + " says " + sth);

sayhello(sth);

person.hello("hello world");//Person says hello world

</td></tr></tbody></table>

ps:匿名函数就是没名字的函数,内部函数就是函数内部的函数,闭包则是指有权访问另一个函数作用域中变量的函数,这三个概念都是指函数,不要混淆了。

6.使用call和apply设置this

apply和call类似,只是后面的参数是通过一个数组传入,而不是分开传入。两者的方法定义:

<table><tbody><tr><td></td><td>

call( thisArg [,arg1,arg2,… ] ); // 参数列表,arg1,arg2,...

apply(thisArg [,argArray] ); // 参数数组,argArray

</td></tr></tbody></table>

两者都是将某个函数绑定到某个具体对象上使用,自然此时的this会被显式的设置为第一个参数.

我们可能经常会写这样的代码:

<table><tbody><tr><td></td><td>

$("#some-ele").click = obj.handler;

</td></tr></tbody></table>

如果在handler中用了this,this会绑定在obj上么?显然不是,赋值以后,函数是在回调中执行的,this会绑定到$(“#some-div”)元素上。这就需要理解函数的执行环境。本文不打算长篇赘述函数的执行环境,可以参考《javascript高级程序设计》中对执行环境和作用域链的相关介绍。这里要指出的时,理解js函数的执行环境,会更好地理解this。

那我们如何能解决回调函数绑定的问题?ES5中引入了一个新的方法,bind():

<table><tbody><tr><td></td><td>

fun.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg

当绑定函数被调用时,该参数会作为原函数运行时的this指向.当使用new 操作符调用绑定函数时,该参数无效.

arg1, arg2, ...

当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数.

</td></tr></tbody></table>

该方法创建一个新函数,称为绑定函数,绑定函数会以创建它时传入bind方法的第一个参数作为this,传入bind方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.

显然bind方法可以很好地解决上述问题。

<table><tbody><tr><td></td><td>

$("#some-ele").click(person.hello.bind(person));

//相应元素被点击时,输出Person says hello world

</td></tr></tbody></table>

其实该方法也很容易模拟,我们看下Prototype.js中bind方法的源码:

<table><tbody><tr><td></td><td>

Function.prototype.bind = function(){

var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();

return function(){

return fn.apply(object,

args.concat(Array.prototype.slice.call(arguments)));

</td></tr></tbody></table>