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
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:
Create a variable called nick if there isn't one with a non-falsey value already
Create an anonymous function that…
Creates a variable called helloA in its own scope
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.
Defines a function called init
Returns an object which gets assigned to nick.name
Then you call nick.name.init() which executes the init function in the context of name.
This defines helloB
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)
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
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.
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.
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).
Related
I'm having issues understanding scoping/access of fields defined with a JavaScript object.
Consider the following sample JavaScript object definition:
function SampleObject(controlName) {
var _controlName = controlName;
this.Display1 = function() {
console.log(_controlName);
}
this.Display2 = function() {
Display3();
}
Display3 = function () {
console.log(_controlName);
}
}
Now consider running the above object with the following example:
var a = new SampleObject("Bob");
var b = new SampleObject("Fred");
a.Display1(); //==> Displays "Bob"
b.Display1(); //==> Displays "Fred"
a.Display2(); //==> Displays "Fred"
b.Display2(); //==> Displays "Fred"
What I'm having difficulty understanding is how to access object fields (properties) from within private functions defined within my object.
Within my example, I am confused as to why _controlName has the value "Fred" when it is displayed via Display2() for both objects a and b.
I suspect that is either an issue with how _controlName and/or Display3() is defined or I am unclear how scoping would work in this instance. Can someone please share some light on this?
Thanks,JohnB
In some other languages such as Java (where I hail from), when you are inside a method on an object, the this is implicit. In Javascript, this is NOT the case.
When you are assigning to this.Display1 and this.Display2, you are creating properties with those names on the object pointed at by this. Because of new, this is a different object each time.
However, what's happening when you assign to Display3 is that you are assigning to a global variable. If it doesn't exist, it is created for you. When you call new SampleObject("Fred"); the function which originally logged "Bob" is now gone, replaced by one which prints "Fred".
If you add 'use strict'; to the top of your SampleObject function, which suppresses this "implicit global" behavior, you get a reference error when you try to assign to the never-declared variable Display3.
Here's the explanation.
In the first call, new SampleObject("Bob"); the global variable Display3 gets set to a function that console-logs the value Bob.
In the second call, new SampleObject("Fred"); the global variable Display3 gets set to a function that console-logs the value Fred.
Now your Display1 is actually a method. Every object you create gets its own Display1 property. So Bob's Display1 logs Bob and Fred's logs Fred.
But because the Display2 methods each call the global Display3 method, they will all log what the function in the last assignment fo Display3 says to log, and that will always be Fred.
Can someone explain in detail what this snippet of js does?
(function (window) {
var test = window['test'] = {};
test.utils = new(function(){ ... })();
})(window);
I understand that the function is not globally scoped. I understand that it is creating a variable called test that points to a property in the window object that is an empty object. I also understand that utils is a property of test.
I don't understand what the purpose of the last part is (window); or why the utils function is being designated as new.
Please explain.
It creates a function and calls it immediately, passing in window. The function receives an argument called window and then creates an empty object on it which is available both as a property on window called test and as a local variable called test. Then it creates an object by calling a function via new and assigns that object to test.utils.
I don't understand what the purpose of the last part is (window);...
It doesn't really serve any purpose in the code you've quoted, because the symbol passed into the main (outer) function, window, is the same as the name of the argument receiving it. If their names were different, then it would serve a purpose, e.g.:
(function(wnd) {
})(window);
That would make window available within the function as wnd.
or why the utils function is being designated as new.
utils won't be a function (at least, not unless the code you've replaced with ... is doing something really strange), it will be an object created by calling that function.
The whole thing could be rewritten more clearly:
(function(window) {
var test;
test = {};
window['test'] = test;
test.utils = new NiftyThing();
function NiftyThing() {
}
})(window);
That still does the window thing for no reason, but hopefully it makes it clear what the new(function() { ... })(); bit was doing.
First of all, this is a self-invoked function.
It's invoked itself giving the window object as function input argument in order to ensure that, inside the whole function, window will have the expected meaning.
test.utils = new(function(){ ... })(); <--- This is an object constructor.
When the function is called using the new operator, it turns into an object constructor.
For example:
var conztructor = function() {
this.name = "Matias";
};
var obj = new conztructor();
alert(obj.name); // <--- This will alert "Matias"!
The purpose of (window); is creating a new variable and reference holding the JavaScript Window object instance, avoiding that other libraries may reuse the window (or any other) identifier and your own library may break because of this situation.
This is nice in order to avoid altering global scope identifiers that may be used by other libraries.
UPDATE
In response to some comments, run this code:
http://jsfiddle.net/wChh6/5/
What is happening here is that a new anonymous function is being declared. The last part with (window) makes a call to that function, passing window as a parameter.
Inside, the call to test.utils = new(function(){ ... })(); creates a new object (with contents defined by the function passed to new) and assigns it to test.utils.
When you define a function with last parentetheses, the function is executed itself after loading with the parameter given, in your case window
(function (window) {
var test = window['test'] = {};
test.utils = new(function(){ ... })();
})(window);
JS function definition : meaning of the last parentheses
This is taken from John Resig`s Learning Advanced Javascript #25, called changing the context of a function.
1) in the line fn() == this what does this refer to? is it referring to the this inside the function where it says return this?
2) although I understand the purpose of the last line (to attach the function to a specific object), I don't understand how the code does that. Is the word "call" a pre-defined JavaScript function? In plain language, please explain "fn.call(object)," and explicitly tell me whether the object in parens (object) is the same object as the var object.
3). After the function has been assigned to the object, would you call that function by writing object.fn(); ?
var object = {};
function fn(){
return this;
}
assert( fn() == this, "The context is the global object." );
assert( fn.call(object) == object, "The context is changed to a specific object."
call is a function defined for a Function object. The first parameter to call is the object that this refers to inside the function being called.
When fn() is called without any particular context, this refers to the global context, or the window object in browser environments. Same rules apply for the value of this in the global scope. So in fn() == this), this refers to the global object as well. However, when it is called in the context of some other object, as in fn.call(object), then this inside fn refers to object.
fn.call(object) does not modify or assign anything to object at all. The only thing affected is the this value inside fn only for the duration of that call. So even after this call, you would continue calling fn() as regular, and not as object.fn().
The example simply demonstrates that the this value inside a function is dynamic.
It is said, javascript clears a variable from memory after its being referenced last.
just for the sake of this question i created a JS file for DEMO with only one variable;
//file start
//variable defined
var a=["Hello"]
//refenence to that variable
alert(a[0]);
//
//file end
no further reference to that variable, so i expect javascript to clear varaible 'a'
Now i just ran this page and then opened firebug and ran this code
alert(a[0]);
Now this alerts the value of variable, If the statement "Javascript clears a variable after there is no further reference it" is true how come alert() shows its value.
Is it because all variable defined in global context become properties of window object, and since even after the execution file window objects exist so does it properties.
Of course the variable HAS to be kept around in this example - after all, you keep the ENVIRONMENT it has been defined in around. As long as you COULD still access it is has to be kept, so if you can make this test and it ever fails - the JS interpreter is "kaputt".
Do this instead:
(function () {
var a = 1;
}());
// and NOW, at THIS point there is nothing any more referencing "a"
Of course, from out "here" you cannot test that - you'd have to look at the internal memory structures of the JS interpreter/compiler (today in the days of V8 it's more like a "interpiler" or "compreter" aynway).
In addition though, like all garbage collecting (GC) languages, the memory is not freed immediately but depending on GC strategy used by the particular implementation of Javascript, which also takes current memory usage and demand into account. GC is a costly operation and is delayed, if possible, and/or run when it does not take away CPU resources from the real app.
By the way, slight variation:
(function () {
var a = 1;
//empty function assigned to global namespace,
//in browsers "window" is the global object
window.example_function = function () {};
}());
In THIS example the result is the same as in yours: as long as you view that page the memory for "a" is NEVER released: the function assigned to property example_function of the global object still exists, so all of the environment is was defined in has to be kept! Only after
delete window.example_function
which deletes that property - which in the end is a pointer to the (empty) function expression - from the global object, could variable "a" be released. Also note that "a" is not even used by that function, see Google and search for "lexical scoping", one of the most defining properties of the Javascript language.
And even more fun:
Had I written
//define a variable in global namespace
var example_function;
(function () {
var a = 1;
//empty function assigned to global namespace,
//in browsers "window" is the global object
example_function = function () {};
}());
I could not use "delete" to remove it, in fact I could not ever release it. That's because in the first example example_function becomes a new property of the global object (emphasis), while in this last example it is a variable, and "delete" works with object properties only. (I used "windows.example_function" in the earlier example, but without the "window." it would have been just the same, example_function would have been created as property in the global object. Only the "var" statement creates variables.)
Is it because all variable defined in global context become properties of window object, and since even after the execution file window objects exist so does it properties.
Yes. You would either have to close the window, or explicitly remove a from the window properties.
A side effect of your script is that there's a property name "a" defined in the global object ( window ), so there is actually still a global reference to a.
(function()
{
var a = 12;
alert(a);
})();
If we wrap the declaration of a in self-executing function like here, a will be inaccessible after the function has exited.
Yes, although you can mitigate this behavior by declaring and acting on your variables within the scope of a function:
( function myfunc(a){
var b = 100;
alert(a); // 200
alert(b); // 100
}(200));
alert(a); // undefined
alert(b); // undefined
Referencing a variable does not mean using it in some manner. As long as there is at least one reference to the variable which can still be accessed, it has to be kept in memory.
Looking at your example, the following line has no effect on whether the variable gets cleared or not. Even if a wasn't being used anywhere, it would still have been kept intact.
//refenence to that variable
alert(a[0]);
Although an object may be created inside a function, its lifetime may extend beyond the function itself. The only thing to remember is whether there are still any valid references to the object in question. Consider this example,
(function() {
var a = ["Hello"];
var copy = a;
a = null;
setTimeout(function() {
// a: null, copy: ["Hello"]
console.log("a: %o, copy: %o", a, copy);
}, 2000);
})();
The variable a is created inside an anonymous function, and another variable copy is referencing it. a is set to null right after, but we still have 1 reference to it from copy. Then we create a timeout which makes another reference to the same variable. Now even though this anonymous function will go out of scope after it executes the setTimeout, we still left 1 reference to it in the timeout function. So this copy variable will still be intact when the timeout function is run.
When we have code like:
function a(){
var x =0;
this.add=function(){
alert(x++);
}
}
var test = new a();
test.add(); // alert 0
test.add(); // alert 1
test.add(); // alert 2
How does this work?
Doesn't that the value of 'x' in a() should be 'gone' as soon as test = new a() is complete? The stack contains x should also be gone as well, right? Or, does javascript always keep all the stacks ever created in case they will be referenced in future? But that wouldn't be nice, would it...?
The word you're looking for is “closure”.
Creating a function inside another function gives the inner function a (hidden) reference to the local scope in which the outer function was running.
As long as you keep a copy of your test, that has an explicit reference to the add function, and that function has an implicit reference to the scope created when calling the a constructor-function. That scope has an explicit reference to x, and any other local variables defined in the function. (That includes the this value and the constructor's arguments — though you can't access them from inside add as that function's own this/arguments are shadowing them.)
When you let go of test, the JavaScript interpreter can let go of x, because there's no way to get a reference back to that variable.
What you're seeing is the effect of a closure. The function being defined within the other function gets access to all of the variables and such in scope where it is — even after the outer function returns. More here, but basically, the variables (and arguments) in the function all exist as properties on an object (called the "variable object") related to that function call. Because the function you've bound to this.add is defined within that context, it has an enduring reference to that object, preventing the object from being garbage-collected, which means that that function can continue to access those properties (e.g., the variables and arguments to the function).
You normally hear people saying that the function closes over the x variable, but it's more complex (and interesting) than that. It's the access to the variable object that endures. This has implications. For instance:
function foo() {
var bigarray;
var x;
bigarray = /* create a massive array consuming memory */;
document.getElementById('foo').addEventListener('click', function() {
++x;
alert(x);
});
}
At first glance, we see that the click handler only ever uses x. So it only has a reference to x, right?
Wrong, the reference is to the variable object, which contains x and bigarray. So bigarray's contents will stick around as well, even though the function doesn't use them. This isn't a problem (and it's frequently useful), but it emphasizes the underlying mechanism. (And if you really don't need bigarray's contents within the click handler, you might want to do bigarray = undefined; before returning from foo just so the contents are released.)