This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
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...?
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.
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."
Related
I created a normal JavaScript object, like this:
let obj = {
name : "something",
print() {
console.log(this.name);
}
}
let res = obj.print()
console.log(res);
In this example obj has a name and a simple method. I am calling the method from the outside. After that I log the return value to the console, which is undefined.
I don't understand what is happening behind the scenes within the object. Please explain to me the creation and execution phase for this code.
Behind the scenes, the JavaScript interpreter creates an object in memory and refers to it through obj. When you call obj.print(), it refers to the same object and calls the method defined.
In the method, this refers to the object itself (obj), and is set by the JS interpreter as an implicit reference.
At last, you forgot to return the value from print(). So, nothing is assigned to res. Refer to the following example, as it prints the value of res correctly, when a value is returned from the function.
let obj = {
name: "something",
print() {
console.log(this.name);
return this.name;
}
}
let res = obj.print()
console.log(res);
I am going to write about the "behind the scenes" that you are asking for. Unfortunately this might confuse you, instead of making things clearer as JavaScript is quite a "different" language on its own.
In JavaScript a function is an object. Sometimes even called a first-class object. It has everything an object has (attributes and methods) and in addition can further more be invoked. Don't believe me? See for yourself:
function abracadabra()
{
return "this is magic";
}
console.log(abracadabra.name);
console.log(abracadabra.call());
Now a method is simply another function to which an attribute of an object is referring to. Let's take your example:
let obj = {
name : "something",
print() {
console.log(this.name);
}
}
Here obj is defined as an object with two attributes. A value type and a function. When you call the obj.print() function the following happens:
The function is called.
The so-called function context this is set to the object that the method is called upon. You can use this to access other attributes of the same object.
What exactly is this? As said it is the so-called function context that can refer to four different objects depending on how a function is called.
The function is called as a function. e.g. abracadabra() => this is referring to the global context, to which it is always referring by default.
The global context is dependent on the environment JavaScript is executed in. Remember JavaScript can not only run in a browser. It can also be used as a server-side scripting language. In the browser the global context is the current browser window. Don't believe me? See for yourself:
// We are not in any method, still "this" is available:
console.log(this.toString());
The function is called as a method. e.g. obj.print() => this is referring to the object the method is invoked on. I described this above.
The function is called as a constructor. e.g. new abracadabra() => A new empty object is created and this is referring to it. Now the function should extend the empty object with attributes.
The function is called using its apply or call methods => this is referring to whatever you pass as the very first argument of these methods.
So to sum it up: It can get tricky to really understand how these things work in JavaScript. This is because basically there are only objects and functions in the language. Methods look like methods, but are in reality only functions as well.
To get a really good in depth understanding I can recommend the book Secrets of the JavaScript Ninja.
Today while working my mind was stack at some point in javascript.
I want to know that what is basic difference between
function FunctionName(){
//Code goes here;
}
And
var MyFuncCollection = new Object();
MyFuncCollection.FunctionName = function(){
//Code goes here;
}
Both are working same. Then what is difference between then. Is there any advantage to use function with object name?
I have read Question. But it uses variable and assign function specific variable. I want to create object and assign multiple function in single object.
The first one defines a global function name. If you load two libraries, and they both try to define FunctionName, they'll conflict with each other. You'll only get the one that was defined last.
The second one just has a single global variable, MyFuncCollection. All the functions are defined as properties within that variable. So if you have two collections that try to define the same function name, one will be FuncCollection1.FunctionName, the other will be FuncCollection2.FunctionName, and there won't be any conflict.
The only conflict would be if two collections both tried to use the same name for the collection itself, which is less likely. But this isn't totally unheard of: there are a few libraries that try to use $ as their main identifier. jQuery is the most prominent, and it provides jQuery.noConflict() to remove its $ binding and revert to the previous binding.
The short answer is, the method in object context uses the Parent Objects Context, while the "global" function has its own object context.
The long answer involves the general object-oriented approach of JavaScript, though everything in JavaScript is an object you may also create arrays with this Method.
I can't really tell you why, but in my experience the best function definition is neither of the top mentioned, but:
var myFunction = function(){};
It is possible to assign function to variables, and you may even write a definition like this:
MyObject.myMethod = function(){};
For further reading there are various online Textbooks which can give you more and deeper Information about this topic.
One main advantage I always find is cleaner code with less chance of overwriting functions. However it is much more than that.
Your scope changes completely inside the object. Consider the following code ::
Function:
function FunctionName(){
return this;
}
FunctionName()
Returns:
Window {top: Window, location: Location, document: document, window: Window, external: Object…}
Object:
var MyFuncCollection = new Object();
MyFuncCollection.FunctionName = function(){
return this;
}
MyFuncCollection.FunctionName()
Returns:
Object {}
This leads to some nice ability to daisy chain functions, amongst other things.
The first:
function functionName (){
//Code goes here;
}
Is a function declaration. It defines a function object in the context it's written in.
Notice: this doesn't have to be the global context and it doesn't say anything about the value of this inside it when it's invoked. More about scopes in JavaScript.
Second note: in most style guides functions are declared with a capitalized name only if it's a constructor.
The second:
var myFuncCollection = {};
myFuncCollection.functionName = function () {
//Code goes here;
};
notice: don't use the new Object() syntax, it's considered bad practice to use new with anything other then function constructors. Use the literal form instead (as above).
Is a simple assignment of a function expression to a property of an Object.
Again the same notice should be stated: this says nothing about the value of this when it's invoked.
this in JavaScript is given a value when the function object is invoked, see here for details.
Of course, placing a function on an Object help avoiding naming collisions with other variables/function declarations in the same context, but this could be a local context of a function, and not necessarily the global context.
Other then these differences, from the language point of view, there's no difference whatsoever about using a bunch of function declarations or an Object with bunch of methods on it.
From a design point of view, putting methods on an Object allows you to group and/or encapsulate logic to a specific object that should contain it. This is the part of the meaning of the Object Oriented Programming paradigm.
It's also good to do that when you wish to export or simply pass all these functions to another separate module.
And that's about it (:
This question already has answers here:
Is 'window' always on top of the scope chain in javascript?
(5 answers)
Closed 8 years ago.
As I understand from my practice (in the Google Chrome Console), we can change the definition of predefined functions. Let me explain through code:
function alert(){
return 2+2;
}
and I am calling alert("hi"), it is returning 4, it's Ok, as we have defined.
But, even when I call window.alert("hi"), it is returning 4, which is unexpected (for me).
Here I just created a new function, I have not mentioned any object name or Prototype property, but still it is overriding the window object properties itself.
My doubt is, if we change the definition of the function, will it override the definitions of a function with the same name in all the objects??
Let's say I have two objects objA and objB, both are having a function named strange(). Now I am defining a function strange() in the outside of both the objects. Then, whether it will override the definition of strange() in both objA nad objB? If so, why?
If so, how to prevent this? means how to prevent the overriding in all the objects?
Thanks in advance...!!!!
No - by declaring function alert() you are redefining window.alert() function because the default scope is window
var newObj = {
alert: function() {
return "this is a functino on my newObj object";
}
};
function alert() {
return 2 + 2;
}
console.log(alert());
console.log(window.alert());
console.log(newObj.alert());
The reason defining alert overrides the window property is because you declared it in the global context; anything declared in the global context will, by default, attach itself to window. To not override the window object, declare your function inside another function (or use a different name):
// This creates an anonymous function
(function() {
// Since alert is defined in this function (not the global scope)
// It won't override window.alert
function alert() { /* Do something */ }
})();
// You can no longer access the old alert here, so alert will refer to window.alert
In addition, if you add alert to a specific object, it will not change the alert of any other object, unless you use a with statement (considered bad practice).
var myNamespace = {
alert: function() { /* Custom alert */ }
}
// Will not change myNamespace.alert
function alert() {}
No I don't think so - with the alert function, the "window." prefix is assumed so really window.alert() and alert() are the same thing. I guess it's a short-cut to stop you havign to type window. all the time.
Regarding your other example, objA.strange() isn't related to objB.strange() (assuming objA and objB are in fact different objects).
the function strange() outside of both these objects is actually in window.strange() (it's implied) so again it's a different function under a different object.
You can, I gather, use prototype to redefine native JS functions, but this is normally undesirable.
If you define a variable or function in the default scope in javascript (creating a function directly inside a <script> tag for instance), it is considered part of the window object (if javascript is executed in a browser environment).
So, when you call (the default) alert, you arev actually calling window.alert.
Let's say I have two objects objA and objB, both are having a function
named strange(). Now I am defining a function strange() in the outside
of both the objects. Then, whether it will override the definition of
strange() in both objA nad objB
A definition of strange outside both the object scope (closure) will not impact the definition of the function (method) in the object. But if you define strange within the object again, the latter one will shadow the previous one.
It boils down to the scope of the function and the closure withing which the function (or variable) is defined.
See also
Functions and function scope from MDN. This will answer most of your questions
Closure from John Resig's Learning Advanced Javascript
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
Today I ran into a very odd problem using Javascript's prototype and the this reference.
Basically, I have two objects. One object makes use of a div element and makes is possible to register an onclick event on the div. The other object makes use of this functionality and registers the onclick event using the first object.
Here is the code:
My first object, which takes care of the div:
DivObject = function() {};
DivObject.prototype.setClickListener = function(clickListener){
document.getElementById("myDiv").onclick = function(e){
clickListener(e);
};
};
My second object uses this functionality:
MainObject = function(){
this.myString = "Teststring";
this.divObj = new DivObject();
this.divObj.setClickListener(this.handleClick);
};
MainObject.prototype.handleClick = function(e){
// do something with e
};
The problem is, that inside MainObject.prototype.handleClick, the this reference refers to the window object, not to the MainObject. So, console.log(this) inside this function logs [Object window].
You can see this behaviour on jsfiddle.
As a workaround, I use the setClickListener function as follows:
var thisRef = this;
this.divObj.setClickListener(function(e){
thisRef.handleClick(e);
});
Now, the this reference in my handleClick function refers to my MainObject (as I want it to be).
See this workaround on jsfiddle.
My questions are:
Why does the this reference one time refer to the window object and one time to the this reference of my object? Is it overridden somewhere? I always thought using this in my object I can be sure that it is really the this reference of my object? Is the workaround I am using now the way how this problem should be solved or are there any other, better way to handle this case?
Your questions:
Why does the this reference one time refer to the window object and one time to the this reference of my object?
Other than using bind, the value of a function's this is set by how the function is called. When you do:
this.divObj.setClickListener(this.handleClick);
you are assigning a function reference, so the function is called later without any qualification (i.e. it's called as just handleClick rather than this.handleClick). On entering the function, because its this isn't set by the call, it will default to the global (window) object, or in strict mode remain undefined.
Is it overridden somewhere?
No, the value of this is set on entering an execution context. You can't overwrite it or directly assign to it, you can only set it in the call (e.g. as a method of an object, using new, apply, call) or using bind (also, arrow functions adopt the this of their enclosing lexical execution context).
I always thought using this in my object I can be sure that it is really the this reference of my object?
At the point you make the assignment, this is what you expect. But you are assigning a reference to a funciotn, not calling the function, so its this isn't set at that moment but later when it's called.
Is the workaround I am using now the way how this problem should be solved or are there any other, better way to handle this case?
Your work around is fine (and a common fix), it creates a closure so may have minor memory consequences but nothing serious. For very old versions of IE it would create a memory leak due to the circular reference involving a DOM object, but that's fixed.
The bind solution is probably better from a clarity and perhaps maintenance viewpoint. Remember to include a "monkey patch" for browsers that don't have built–in support for bind.
Please post code on SO, there is no guarantee that code posted elsewhere will continue to be accessible. The work around code:
MainObject = function(){
this.myString = "Teststring";
this.divObj = new DivObject();
var thisRef = this;
this.divObj.setClickListener(function(e){
thisRef.handleClick(e);
});
};
You could fix this by using .bind():
this.divObj.setClickListener(this.handleClick.bind(this));
See the demo.
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).