Unexpected scope question

R

risingfish

Hello, I would call myself a fairly competent JavaScript programmer,
but I ran into something expected today. Here's a snippet:

NS.MyClass = function () {

var initialize = function() {
/* do something */
NS.Instances[<uniqueId>] = this;
}

initialize();
}

var obj = new NS.MyClass();

The object that ends up in NS.Instances[<uniqueId>] is DOMWindow, not
the particular instance of that class. I can obviously fix it with
call() but I've found a hole in my knowledge and am trying to
understand. Could someone explain what is happening there?

Thanks!
R
 
M

Michael Haufe (TNO)

Hello, I would call myself a fairly competent JavaScript programmer,
but I ran into something expected today. Here's a snippet:

NS.MyClass = function () {

    var initialize = function() {
        /* do something */
        NS.Instances[<uniqueId>] = this;
    }

    initialize();

}

var obj = new NS.MyClass();

The object that ends up in NS.Instances[<uniqueId>] is DOMWindow, not
the particular instance of that class. I can obviously fix it with
call() but I've found a hole in my knowledge and am trying to
understand. Could someone explain what is happening there?


The bigger question is why you've decided to write JavaScript in this
manner. Why do you have an inner function in the first place?
 
S

Scott Sauyet

Hello, I would call myself a fairly competent JavaScript programmer,
but I ran into something expected today. Here's a snippet:

NS.MyClass = function () {

    var initialize = function() {
        /* do something */
        NS.Instances[<uniqueId>] = this;
    }

    initialize();

}

var obj = new NS.MyClass();

The object that ends up in NS.Instances[<uniqueId>] is DOMWindow, not
the particular instance of that class. I can obviously fix it with
call() but I've found a hole in my knowledge and am trying to
understand.

From version 5.1 of the ECMA-262 spec (June, 2011) [1]:

| 10.4.3 Entering Function Code
| The following steps are performed when control enters the execution
| context for function code contained in function object F, a caller
| provided thisArg, and a caller provided argumentsList:
|
| 1. If the function code is strict code, set the ThisBinding to
thisArg.
| 2. Else if thisArg is null or undefined, set the ThisBinding to the
| global object.
| 3. Else if Type(thisArg) is not Object, set the ThisBinding to
| ToObject(thisArg).
| 4. Else set the ThisBinding to thisArg.
| ...

So, when you call `initialize` from within your constructor function
without specifically binding `this`, the ThisBinding defaults to the
global object.

As you say, you can fix this with `call`:

| initialize.call(this);

You also might want to reconsider having the initialize function
redefined for each call to the constructor by storing it in a local
closure. Or, if it's as simple as what you've exposed here, remove
the inner function altogether, as Michael suggests.

-- Scott

[1]: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top