1

I am creating a program which will, ultimately, create thousands of small objects (ideally about 60,000 of them), each containing specific information. It will be loading each object from a small JSON file which has already been created and is sitting within a directory tree structure on the server.

How it finds the files is immaterial to this question (let's say it's outside the "scope" of it) however I'm trying to understand how this works by stepping through the program.

Assume that I have simplified this somewhat as well; as I know many of you may catch that I seem to be adding an unnecessary layer between my request to load the data and actually loading it (which obviously I could via jQuery's $.getJSON().done()), however since there's the file system structure to take into account, the program also needs to handle that part as well.

Data = function() {

    var VERSION = 1.1;

    if (this.constructor === Data) {

        throw new Error("Objects may not be directly instantiated from an abstract class.");
    }
}

// Loads a file with the path from the root set in config.json

Data.prototype.loadData = function(treePath,callback) {

    // does data loading stuff here and proceeds through, eventually getting to this line: 
            callback(req,loadedData);

}

Now, I've got an abstraction layer in there - I don't want the Data object to be created in and of itself, which is why it throws and error should someone call "new Data();" That's intentional.

I will then have two objects which inherit Data; both with methods which deal with the loaded data in different ways. Since the file tree structure is the same for both, however, it makes sense to create an abstract object to inherit from. (OR, as a sub-question, is this a good argument for an object literal for the Data object?)

Now, I call the loadData from FOO and then Data will call the callack, which is inside FOO. I have tried declaring this as FOO.prototype.pareseData, and FOO.parseData, and it makes no difference.

FOO.parseData = function(req,path) { 

    // Parse the data and deal with it as needed.
}

Stepping through, when I call FOO from the main program and tell it to start loading the data, I can watch the "this" value. Initially, this = FOO, as expected; and this remains FOO until Data calls the callback function.

Once the code hits FOO.parseData, this changes from FOO to "window".

And I have no idea why...?

  • 1
    What's `FOO`? I don't see it defined anywhere – CodingIntrigue Apr 15 '15 at 13:13
  • 2
    When there is a lot of text, people complain about it, when theres too less text, people complain about it... – taxicala Apr 15 '15 at 13:20
  • RGraham - assume that FOO is declared and instantiated correctly. I left it out because it really doesn't add much to the question except for a few extra lines of code. – Steven C. Britton Apr 15 '15 at 13:29
  • @thefourtheye You are seriously going to complain about the question because I take the time to explain it in plain English? if it bothers you, move on. There are tons of people on here willing to help who aren't bothered by it, so find a question which suits your own preferences. I'm verbose because I want to be clear what I'm asking about. – Steven C. Britton Apr 15 '15 at 13:36
  • 2
    @StevenC.Britton (S)he's just pointing out that you'll get more help on Stack Overflow if you are concise. That is a fact, based on the time (s)he has been on this site and the experience they've gained. You are free to ignore that, but don't take it as a personal insult on your writing skills. – CodingIntrigue Apr 15 '15 at 13:41
  • @RGraham Thanks for that; it just seems a little odd to me that it would be worth anyone's time to make a comment like that rather than contact me privately - if possible - to discuss something like this. I know I'm a decent writer, and maybe I do go on a bit at times, but still... Anyway, moving on... – Steven C. Britton Apr 15 '15 at 13:45
  • Your actualy question "*`this` changes from `FOO` to `window`. And I have no idea why...?*" is answered by the dupe, or the [docs on `this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this). But apart from that, I would want to advice against a) loading 60000 files from a server and b) do the loading of the data [inside the class](http://stackoverflow.com/q/24398699/1048572) – Bergi Apr 15 '15 at 13:48
  • @Bergi Could you expand on that? is there a different approach you'd take? – Steven C. Britton Apr 15 '15 at 13:49
  • 1
    Yes, make a loader function that does the server requests and constructs the `Foo` and `Bar` instances by passing the bit of data to the respective constructors. If your foos and bars don't share any common methods, they don't even need a superclass, but you're a bit vague on that. And instead of making 60000 requests to your server, you should definitely bundle the files (possibly dynamically, on the server side) and make only a few big requests. – Bergi Apr 15 '15 at 13:53
  • @Bergi ultimately, since the 60,000 files are the "building blocks" of several clumps of larger groups of data that I have pre-bundled anyway, but would want to have access to, I may make it an on-demand thing rather than a bulk load at startup. it will all depend on the load and how efficiently the data can get displayed. but thanks for that - I'll look into re-jigging the setup to account for the suggestion. – Steven C. Britton Apr 15 '15 at 14:48

2 Answers2

1

Thats because in javascript, "this" is a reference to the current scope, so, If you call a function/callback outside the original scope, most probably that "this" will be the "window", since "window" is the one that is calling the function/callback.

A workaround in order to maintain "this" to the scope you want to, you have to bind your functions to that given scope when you are declaring it:

function Foo() {
    this.bar();
}.bind(this); //-> Here you bind Foo to the current scope, so inside Foo, this will be always the scope where it was bound.
taxicala
  • 21,408
  • 7
  • 37
  • 66
  • 1
    `this` does not refer to the scope! Whike they are related, they are different things. – Felix Kling Apr 15 '15 at 13:35
  • @FelixKling thanks for that, Felix. "this" refers to the object itself, which is, in essence, the scope that we're working within. Call it "context" or whatever if you want, and I get that we probably need to define things like this clearly. okay, so I'm new to the game... bear with me, k? ;) – Steven C. Britton Apr 15 '15 at 13:47
  • @Steven: of course when communicating with others and trying to teach, using the correct terminology is of the essence :) And "scope" has a very specific meaning in programming languages. It describes the "region" where a variable is visible. `this` is not scope. It does not let you access the variables in a scope (exception is the global scope, because in JS global variables are properties of the global object). Usually local variables are not properties of an object. – Felix Kling Apr 15 '15 at 13:55
  • @FelixKling thanks for that, Felix. I try to use the correct terminology, of course. As I said, though, I'm learning :) – Steven C. Britton Apr 15 '15 at 13:56
  • 1
    I'm going to mark this as the answer, because it gives me some good information that I can use. The link provided is probably useful to, but since this is about asking questions and getting answers, this one fits the bill the best. – Steven C. Britton Apr 15 '15 at 20:19
  • 1
    Glad I could help you out, at least with some usefull information :) – taxicala Apr 15 '15 at 20:20
1

I strongly recommend you to read this article.

http://ryanmorr.com/understanding-scope-and-context-in-javascript/

Your problem is explained in 3rd paragraph - What is “this” Context:

"Context is most often determined by how a function is invoked. When a function is called as a method of an object, this is set to the object the method is called on:

var obj = {
    foo: function(){
        alert(this === obj);    
    }
};
obj.foo(); // true

The same principle applies when invoking a function with the new operator to create an instance of an object. When invoked in this manner, the value of this within the scope of the function will be set to the newly created instance:

function foo(){
    alert(this);
}
foo() // window
new foo() // foo

When called as an unbound function, this will default to the global context or window object in the browser. However, if the function is executed in strict mode, the context will default to undefined."

Vasilev
  • 111
  • 7
  • To maintain the quality of the site, it would be better if you could quote the sections you feel that are important from other resources. Link only answers are not very reliable as the link might get broken. – thefourtheye Apr 15 '15 at 13:22