0

I've been reading through quite a few articles on the 'this' keyword when using JavaScript objects and I'm still somewhat confused. I'm quite happy writing object orientated Javascript and I get around the 'this' issue by referring the full object path but I don't like the fact I still find 'this' confusing.

I found a good answer here which helped me but I'm still not 100% sure. So, onto the example. The following script is linked from test.html with <script src="js/test.js"></script>

if (!nick) {
 var nick = {};
}
nick.name= function(){
 var helloA = 'Hello A';
 console.log('1.',this, this.helloA);
 var init = function(){
 var helloB = 'Hello B';
 console.log('2.',this, this.helloB);
 }
 return {
 init: init
 }
}();
nick.name.init();

What kind of expected to see was

1. Object {} nick.name, 'Hello A'
2. Object {} init, 'Hello B'

But what I get is this?

1. Window test.html, undefined
2. Object {} init, undefined

I think I understand some of what's happening there but I would mind if someone out there explains it to me.

Also, I'm not entirely sure why the first 'console.log' is being called at all? If I remove the call to the init function //nick.name.init() firebug still outputs 1. Window test.html, undefined. Why is that? Why does nick.name() get called by the window object when the html page loads?

Many thanks

asked Apr 28, 2010 at 11:09

4 Answers 4

3

Also, I'm not entirely sure why the first 'console.log' is being called at all?

nick.name = function(){
 // ...
}();

Here you define a function, call it immediately (hence ()) and assign its return value ({init: init}) to nick.name

So the execution is:

  1. Create a variable called nick if there isn't one with a non-falsey value already
  2. Create an anonymous function that...
  3. Creates a variable called helloA in its own scope
  4. Outputs data using console.log containing "1" (as is), this (the window because the function is executing in the global context instead of as a method), and this.helloA (window.helloA, which doesn't exist.
  5. Defines a function called init
  6. Returns an object which gets assigned to nick.name
  7. Then you call nick.name.init() which executes the init function in the context of name.
  8. This defines helloB
  9. Then it console.logs with "2" (as is), this (name), and this.helloB (nick.name.helloB - which doesn't exist)

So the first output you get is from console.log('1.',this, this.helloA);

I think your main problem is that you are confusing this.foo (properties on the object on which a method is being called) with variable scope (variables available to a function)

screenm0nkey
18.9k18 gold badges62 silver badges75 bronze badges
answered Apr 28, 2010 at 11:18
Sign up to request clarification or add additional context in comments.

2 Comments

I didn't say it defines helloB in the context of lowman. It defines in the scope of lowman. A variable existing in a given scope is not the same as a property on an object.
Thanks so much for your help David. I've spent the morning creating some examples and I think I'm slowly getting it.
2

It's much simpler if you think about this as a function, not as a variable. Essentially, this is a function which returns current "execution context", that is, the object the current function was "applied" to. For example, consider the following

function t() { console.log(this)}

this will return very different results depending upon how you call it

t() // print window
bar = { func: t }
bar.func() // print bar
foo = { x: 123 }
t.apply(foo) // print foo
answered Apr 28, 2010 at 11:23

2 Comments

Foo isn't be a function here so it won't have an apply method. I think you meant t.apply(foo). The apply method let's you define the execution context (value of this) explicitly as the function is invoked. (see also Function.call) The flexibility JavaScript has in this sense can be a very powerful tool but it is also a source of great frustration, particularly before you get your head around it!
Thanks for the reply stereofrog. Can I just ask about foo.apply(t)? Was that a mistake? Should it be t.apply(foo) //print foo? Many thanks
2
  1. this is defined on a per-function basis when the function call is made. When you call a function as o.f(), this will be o within the function, and when you call it as f(), this will be the global object (for browsers, this is the window). You wrote nick.name = function(){...}(); and the right-hand part is of the form f(), hence the Window.

  2. var foo = bar; defines a local variable. It may not be accessed as this.foo (well, except when you're at global scope, but that's silly). To define a member, you usually write this.foo = bar; instead.

screenm0nkey
18.9k18 gold badges62 silver badges75 bronze badges
answered Apr 28, 2010 at 11:21

2 Comments

Victor, that was great answer thanks. Do you know why the window object called the function?
To be exact, when you call a function on its own (not as a member), this is the global object, which for web browsers is Window.
1

This is what your code does:

  • It creates an object and assigns to the variable nick.
  • It creates an anonymous function.
  • It calls the function (in the window scope).
  • It assigns the return value (an object containing the init property) to the name property of the object.
  • It gets the value from the init property, which is a method delegate, and calls the method.

The anonymous function does this:

  • It declares a local variable named helloA and assigns a string to it. (Creating a local variable doesn't add it as a property to the current object.)
  • It logs this (window) and the helloA property (which doesn't exist).
  • It creates an anonymous function and assignes to the local variable init.
  • It creates an object with the property init and the value from the local variable init.

The anonymous function assigned to the init property does this:

  • It declares a local variable named helloB and assigns a string to it. (Creating a local variable doesn't add it as a property to the current object.)
  • It logs this (the object from the name property, not the nick variable), and the helloB property (which doesn't exist).
screenm0nkey
18.9k18 gold badges62 silver badges75 bronze badges
answered Apr 28, 2010 at 11:28

2 Comments

so should I use the this keyword when apply variables to an object i.e. this.helloA or does that make private varaibles become public?
@Nick: That depends on the current context. If the context is an object, you can use the this keyword to access the object. If it's the default context (window) you will be adding properties to the window object, thus making them global/public.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.