1

I'm sorry to ask such a basic question but despite lots of reading on javascript over the last few months and on this issue specifically, I'm just not getting something about it's execution context and "this". So I'm hoping an explanation using my specific scenario will help. I have a constructor in which I have some local functions and some exposed functions (mimicking public/private methods).

function blog() {
    if (!(this instanceof blog))
        return new blog();

    function internal(){
        alert(this);
    }

    this.external = function(){
        alert(this);
        internal();
    }
}

var b = new blog();
b.external();

In external, "this" is b, an instance of blog as I expect. I was wrongfully expecting this to hold true inside internal as well, but it's actually the global window object. As an experiment I tried changing external's call to this.internal() which gives an error that this.internal is not a function. This is when I realized I'm really not following how it's working. Ok, I haven't defined a property of blog named internal, but if internal isn't a function defined on my blog instance, what is it and where is it defined? Maybe I have this structured wrong.

xr280xr
  • 12,621
  • 7
  • 81
  • 125
  • Possible duplicate of this: http://stackoverflow.com/questions/2719643/javascript-this-points-to-window-object This one appears to be a better example: http://stackoverflow.com/questions/12241696/why-the-code-this-point-to-window-object – Kyle Muir Apr 16 '14 at 00:46
  • See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this and http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback. – Felix Kling Apr 16 '14 at 02:06

2 Answers2

0

Please see xdazzs answer here: https://stackoverflow.com/a/12241726/2469255

However, to solve your problem you need to define what this is to that function.

Your internal call is called without providing a this context so it binds to the global object, unlike you this.external which has scoped it to the blog object. rewriting your code as follows will solve this:

function blog() {
    if (!(this instanceof blog))
        return new blog();

    function internal(){
        console.log(this);
    }

    this.external = function(){
       console.log(this);
       internal.bind(this);
       internal.call(this); // this in internal will be the object blog.
    }
}

var b = new blog();
b.external(); //blog {external: function} blog {external: function}

Alternatively a lot of people prefer the var self = this to ensure problems like this don't occur and you know exactly what's being set, where. There's a lot of contention over that particular thought so YMMV

Community
  • 1
  • 1
Kyle Muir
  • 3,875
  • 2
  • 22
  • 27
  • I'm more confused after reading that link. The code is too convoluted. However, it's a good example of the kind of answer I'm looking for except using my code example. I understand *what* it's doing and that I can use call/bind/apply to modify "this", but not why it's doing it. I actually don't even need to use "this" in my `internal` so everything's working, I'm just trying to understand JS' behavior. So are you saying any function call defaults to window unless you tell it otherwise? Does the `internal` function belong to `blog` or window? – xr280xr Apr 16 '14 at 02:10
  • 1
    @xr280xr: It's a local function inside `blog`. `this` refers to `window`, because you call the function as `internal()`. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#Simple_call. The value of `this` is only determined by *how* the function is called. – Felix Kling Apr 16 '14 at 02:11
  • Thanks @Felix, good link. I think I get it now. Maybe it's simpler than I thought. It feels strange to have the context unrelated to the scope the function was defined in! So I can't call `this.internal()` because it's not a property of `blog`, but I can call `internal()` because it's in the same scope that `external` was created in, right? A closure? – xr280xr Apr 16 '14 at 02:34
0

Let me try to explain.

This piece of code bellow will only be reachable, if you simple call blog() without a new key word.

if (!(this instanceof blog))
    return new blog();

But, this is not a recommended pratice, cause it's affecting the clearly of your code.

Because this:

var realObj = new Blog();

is the right code to instantiate an Object and the code bellow:

var obj = blog();

are not clear enough and could guide you to mistakes.

JavaScript have originally a Prototypal Inheritance and you have a better explaination here from Douglas Crockford.

The main reason that internal() don't have the same reference from external is because internal have a scope pointing to global and when you create an instance of blog the external scope are pointing to object blog.

Really confuse because this inside the declaration of blog are pointing to global, so why when you instantiate blog this change?

When browser start to read your code, it put what it found in memory, referencing by the scope. Remember scope are controlled with {}, so when he found your declaration this.external he associate to the scope and when you declare using new this become the scope of the object so this don't refer anymore to global scope.

take a look at this code at jsbin.com

Claudio Santos
  • 1,307
  • 13
  • 22
  • I don't see how that code would generate a stack overflow. If I run `new blog()` it creates an instance just fine. `if (!(this instanceof blog)) return new blog();` is commonly you used to make `blog()` (i.e. calling the function without the `new` keyword) work as `new blog()`. And you talk a lot about *scope*, but how `this` works doesn't have *anything* to do with scope. – Felix Kling Apr 16 '14 at 02:08
  • Yes, you are right, but this is not recommend pratice. – Claudio Santos Apr 16 '14 at 02:14
  • 1
    Says who? It's a pretty simple solution to achieve that pattern. But aside from that, it has nothing to do with the OP's question. – Felix Kling Apr 16 '14 at 02:17
  • Thanks for your input @claudio ensuring this is an instance of blog in the constructor seems good to me. If I want to set properties on blog (`this.someProp = "whatever"`) I the constructor, I want to be sure my code is not creating these properties on the global object. – xr280xr Apr 16 '14 at 02:26
  • Simple @FelixKling , turn something into a thing that's originally don't is, is a bad practice, some other who see your code will not understand. For me this is a good reason. – Claudio Santos Apr 16 '14 at 02:29
  • Yes @xr280xr , this works but I still recommend that you do not use and take efforts to make your code sufficiently clear. – Claudio Santos Apr 16 '14 at 02:39
  • @Claudio, I get your point. For my intended use, I gamble it's more likely someone will unintentionally call `blog()` without the new keyword resulting in all the properties intended for the `blog` instance being created on and polluting the global object. So we are still running into "turning something into a thing that's originally don't is", I think (though I'm kind of guessing at exactly what you mean by that). This increases its usability. In my actual code, I have a comment explaining what it is doing so I don't see a down-side. I will reconsider its usage on a case-by-case basis though. – xr280xr Apr 16 '14 at 02:49