that=this in javascript

Watch Out: Callbacks And Closures Sometimes Do Not Play Nicely

Of course there are always gotchas with JavaScript. Lets define a callback function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var createCallBack = function() { //First function
    return new function() { //Second function
        this.message = "Hello World";

        return function() { //Third function
            alert(this.message);
        }
    }
}

window.onload = createCallBack(); //Invoke the function assigned to createCallBack

Lets examine the above code. There are three function operators:

  1. The first function operator creates a function object and is assigned tocreatCallBack.
  2. The second function operator uses the constructor invocation pattern to create a new object.
  3. The third function operator is the result of the return statement. It is a function object and because it is an instance of Object, it gets returned instead of a new object (even though though the function was invoked with new – read constructor invocation pattern for more info).

When invoking the createCallBack variable, what gets passed to the window.onloadevent handler is the result of what is returned by the seond function operator, which is the code in the third function operator. Did you get that? Read this paragraph again until you understand, and if not, stick this code into your browser and play with it.

The above code looks alright, except that undefined gets alerted to the screen (try it for yourself). It turns out that when an event handler invokes a callback function, the function invocation pattern is used. This results in the this parameter being bound to the global object (it is one of the pitfalls of the function invocation pattern) instead of to the object that was created with the constructor invocation pattern. To note that this problem only occurs when one uses the constructor invocation pattern with callbacks like I have illustrated above. To get around this, apply the standard fix for function invocation by declaring a that variable to point to this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var createCallBack = function() { //First function
    return new function() { //Second function
        var that = this;
        this.message = "Hello World";

        return function() { //Third function
            alert(that.message);
        }
    }
}

window.onload = createCallBack(); //Invoke the function assigned to createCallBack

Since the function invoked by the event handler (the third function) is a closure, it has access to the that variable (which is private), and so it has access to the new object created by the constructor invocation pattern.

Read More

 

JavaScript 中的函数既可以被当作普通函数执行,也可以作为对象的方法执行,这是导致 this 含义如此丰富的主要原因。一个函数被执行时,会创建一个执行环境(ExecutionContext),函数的所有的行为均发生在此执行环境中,构建该执行环境时,JavaScript 首先会创建 arguments变量,其中包含调用函数时传入的参数。接下来创建作用域链。然后初始化变量,首先初始化函数的形参表,值为 arguments变量中对应的值,如果 arguments变量中没有对应值,则该形参初始化为 undefined。如果该函数中含有内部函数,则初始化这些内部函数。如果没有,继续初始化该函数内定义的局部变量,需要注意的是此时这些变量初始化为 undefined,其赋值操作在执行环境(ExecutionContext)创建成功后,函数执行时才会执行,这点对于我们理解 JavaScript 中的变量作用域非常重要,鉴于篇幅,我们先不在这里讨论这个话题。最后为 this变量赋值,如前所述,会根据函数调用方式的不同,赋给 this全局对象,当前对象等。至此函数的执行环境(ExecutionContext)创建成功,函数开始逐行执行,所需变量均从之前构建好的执行环境(ExecutionContext)中读取。

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s