Click here to Skip to main content
15,886,026 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
JavaScript
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var calculateBonus = function() {
    alert(this);
    return (this.salary + 1000);
  }
  calculateBonus();
}

var testObj = new Employee();


In this code when we create an object of "Employee" using "new Employee()", "calculateBonus" function is executed while creating the object. When "calculateBonus" is executed, we alert the reference of this, the output of the alert gives a "Window" reference. So "this.salary" in "calculateBonus" function binds salary to window object.

Why the "calculateBonus" function executed under the context of "Windows" and not in context of "Employee"

What I have tried:

I am trying to figure out how to resolve the scope problem for this issue. Please help me in understanding the concept.
Posted
Updated 30-Jun-16 4:27am

In Javascript, "this" is a tricky concept. Many articles have been written trying to explain the complications - for example:

In this case, when you call the calculateBonus function, it doesn't have an explicit context. If you were using strict mode[^], then within the function, this would be undefined. But, since you're not using strict mode, the older rules apply, and this automatically resolves to the global context.

You can work around that using either call[^] or apply[^] to pass in the context:
JavaScript
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  
  var calculateBonus = function() {
    alert(this);
    return (this.salary + 1000);
  };
  
  calculateBonus.call(this);
}

NB: The calculateBonus function doesn't update the Employee object, and the value returned from the function isn't used anywhere. You'll probably want to fix that.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 29-Jun-16 18:49pm    
I 5ed the answer, but did not read the articles you referenced. I did not like what I read before on the topic; it's not so clear or helpful.

At the same time, "this" can be understood very easily by one approach which is psychologically somewhat difficult to many, including myself. One would need to clear one's mind from thinking of JavaScript as of "traditional" OOP system with classes. It's very important to understand that JavaScript programming with prototypes and constructors is very far from the illusionary similarity with OOP: none of those concepts are analogous to classes or class instance constructors; in JavaScripts they are... much simpler. It's really all about objects, not types (the JavaScript concept of type is another non-analogous concepts; and the prototypes are just object prototypes, and constructors are just "normal" functions with "this".

I hope you will like my other answer, Solution 2, more exactly, another reference to the article about the "distractions". :-)

—SA
Sergey Alexandrovich Kryukov 29-Jun-16 19:45pm    
I just added some analysis closer to the inquirer's situation, in addition to your answer. Please see Solution 3, especially the very last (unrelated) code sample — this is pretty interesting.

...and Solution 6. I credited your use of .call, as I explained other cases of passing "this".

—SA
Please see my comment to the Solution 1. In addition to that, I want to say:

It's really important to clear the mind from OOP ideas. This is what is called "distractions" in this article: JS Objects: Distractions.

I seriously advise to learn and and understand well.

As to your example, I seriously advise you to use strict mode. It will quickly clean up your mind from some of the "distractions". Please see: Strict mode — JavaScript | MDN.

One important thing it does: alert(this) will show undefined. This is very important improvement over the dreaded non-strict execution which would immediately give you the required food for thought.

—SA
 
Share this answer
 
v2
Comments
[no name] 30-Jun-16 1:48am    
Thanks a lot for the solution you provided.

But in the case specified above, "alert(this)" is returning "Window" object when executed in non strict environment.

I was trying to evaluate how the function is executed and how we resolve the scope. Can you please explain why the scope of "calculateBonus" is "window" instead of the Employee Object
Sergey Alexandrovich Kryukov 30-Jun-16 10:34am    
Your idea that "this" is related to the scope is wrong. It is totally irrelevant to the scope.

It is related to the concept of the relationship between an object having property and an object used as a property. Note that 1) a function is also an object, 2) and this object can be a property; in this case, "this" is actually passed as an argument.

It you understand that and dismiss your scope misconception, you can probably easily understand the rest. I describe the functioning of "this" in Solution 6.

—SA
I hope you enjoyed the link I provided in Solution 2. Now, let's see what's going on with your simple case. One of the possible solutions would be this:

JavaScript
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  // make alculateBonus a property:
  this.calculateBonus = function() {
    alert(this.name); // "Mayank"
    return (this.salary + 1000);
  }
  this.calculateBonus();
}

Let's assume you are using strict mode in all cases. Non-strict behavior is too confusing to use during development. In your original code, alert would show the window object, which is plain wrong (or, those obsolete wrong decisions!) and hard to recognize what is that. I output this.name only to show some evidence that this is correct "this". (In the style of the sayings by Rabbit from Miln's Winnie-the-Pooh: "'this' can be different!". :-))

Of course, in this particular piece of code, making calculateBonus would be utterly impractical, because this is not what you meant to do; you probably did not want to expose this function to the object users. I'm pretty much sure that you knew the practical solution; only it would be not useful to uncover the "mystery" of "this". So, just in case:
JavaScript
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  calculateBonus = function(owner) { // not a property!
    alert(owner.name);
    return (owner.salary + 1000);
  }
  calculateBonus(this);
}

Now, let's say, you want to use the closure. Great! This is actually much better idea than using properties. I hope the solution would be obvious:
JavaScript
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var name = this.name;
  var salary = this.salary;
  var calculateBonus = function() { // use closure
    alert(name);
    return (salary + 1000);
  }
  calculateBonus();
}

Let's make another step. Why would we need "calculateBonus" at all. Get rid of it:
JavaScript
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var name = this.name;
  var salary = this.salary;
  (function() { // use closure
    alert(name);
    return (salary + 1000);
  })();
}

Much better, isn't it? Please see Pluralitas non est ponenda sine necessitate, see also:
Occam's razor — Wikipedia, the free encyclopedia,
Immediately-invoked function expression — Wikipedia, the free encyclopedia.

Another variant combining some of the above:
JavaScript
function Employee() {
  this.name = "Mayank";
  this.Age = 26;
  this.salary = 10000;
  var owner = this;
  (function() { // use closure
    alert(owner.name);
    return (owner.salary + 1000);
  })();
}




Now, I want to introduce another exciting feature of strict mode. It can help you by taking out false freedom of using the constructors. Try this:
JavaScript
function ConstructorInFact() {
	this.A = 13;
	return 14;
}

var a = new ConstructorInFact();
var b = ConstructorInFact();

I hope that you can see how this code is silly. If this is used as a constructor (a), return 14 is not used. If it is as not a constructor call (b), "this" is pointless. However, all this will work in non-strict mode. Some say it's nice, but it won't detect the silliness of this code. Switch to the strict mode and, for a first attempt, comment out the last line (b). Still, it will work.

Uncomment the last line. In want line the problem will be detected. Surprise: in the line "this.A =…": "this is undefined". Note that the problem only exists if the last line is there.

Wait a minute! Isn't JavaScript an interpreter? No, it is not a pure interpreter. The script is first lexically analyzed. Another surprise? :-)

—SA
 
Share this answer
 
v5
Comments
[no name] 30-Jun-16 1:50am    
Thanks for the reply sir. Its great to see the workarounds for the code I wrote in order to execute it as expected.

Thanks a lot....

But I would also like to know why the above code is Alerting me with the "Window" Object instead of Employee Object
Sergey Alexandrovich Kryukov 30-Jun-16 9:41am    
Because if non-strict mode. This is just weird obsolete behavior. In strict mode, it's always "undefined" object.
Isn't it obvious why it is undefined? Why should it be anything else? "this" is hidden function parameter, which is missing in this case.
—SA
Sergey Alexandrovich Kryukov 30-Jun-16 10:28am    
I answered in detail in Solution 6. Please see. I hope you will also accept it formally.
—SA
[no name] 30-Jun-16 1:59am    
What i assume is that when "new Employee()" is called, it does following things:

1. Create a separate memory block for it.
2. Assign properties to Object
3. Assign "this" to object
4. Return "this"

What I assume is that the code "new Employee()" is called from the global scope. While the global scope is executing the specified steps, it encounters a function "calculateBonus". The function is now executed under the global context since the new object is still not created.

So when this function is executed from the global scope, therefore the context of function execution becomes "global" and therefore "alert(this)" gives "window" object.

Please tell me if my assumption is correct or not. Or there is some problem in understanding the scope resolution for this function.

Regards,
Mayank Gupta
Sergey Alexandrovich Kryukov 30-Jun-16 9:39am    
Not true. There is no such thing as "assign this". "This" and "object" is the same. Return "this" is... well, not accurate. To check up up, write "return 3" at the end. You will see that the instance is still returned via new Employee(); that is, there is a separate mechanism for returning a result of construction. There are two ways too call a function f(): var a = f() and var a = new f(). In second case, return is ignored and newly constructed object is taken. "this" is only a name for the object passed to a function. In your case, nothing is passed.
—SA
Mayank Gupta asked:
Thanks for the reply sir. Its great to see the workarounds for the code I wrote in order to execute it as expected.

Thanks a lot....

But I would also like to know why the above code is Alerting me with the "Window" Object instead of Employee Object
Please see my comment to that question. I though this is obvious.

I already explained that Window Object is the weird artifact of action of the obsolete and unreasonable behavior of JavaScript non-strict mode. You probably understand that the backward compatibility for JavaScript is very serious. This is the only language supported by all browsers. That's why strict mode was created — see Solution 2 and the link. In strict mode, the object "this" is the "undefined" object. By the way, this is a special unique predefined object of the special type "predefined" (not "object"). In strict mode, "this" also can be the reference to the current window object, but only when it is strictly so, when a function is really a property of this object, but to understand it, we will need to discuss it later.

From this point, let's discuss only the cases when strict mode is used, for strictness. :-)
The keyword "this" is used as an argument of a function used inside the implementation of this function, nothing else. So, you need to understand that "this" is a keyword used to access an actual argument of a function. This is a special function argument passed to the function implicitly, not explicitly, that is, it is never appears in an formal argument list. But this argument may or may not be actually passed. It is passed only in some cases:

[EDIT]

Last item of the above list should be understood "dynamically". It does not really matter if some function object is used as a property, it only matters if the function is called via this property or not. Compare:
JavaScript
var object = [];
object.property = "some property";
object.someFunctionProperty = function() {
	alert(this.property);
}

// will alert "some property":
object.someFunctionProperty();

// but
var f = object.someFunctionProperty;
// will alert "undefined":
f();   

[END EDIT]

As always with JavaScript, if you use some undefined object name is, say, assignment to some variable, this variable starts to reference undefined. This is exactly what happens if this is not actually passed at all. In your case, the function is a local function object; that is, a stack variable. None of the mechanisms which could pass this applies.

Finally, there is one marginal case of this object: use it on the top-level script. Let's say, you don't have any functions at all in your whole page. What is this? It's easy to try. It will reference current window object, in both strict and non-strict modes. It tells you that the top-level script is actually always a function; the JavaScript runtime passed the current window object as this argument to it.

—SA
 
Share this answer
 
v2
Comments
[no name] 1-Jul-16 1:51am    
Thanks for the solution. It was really good to learn from the solutions provide.

It was just that I was trying to figure out how browser behaves without strict mode.
[no name] 1-Jul-16 1:54am    
If you don't mind, Can I ask if the "Solution 5" can be taken as a semi valid reasoning for the above problem I specified even if we consider that it behaves in strange manner in Browser without strict mode.
Thanks for the reply sir. Its great to see the workarounds for the code I wrote in order to execute it as expected.

Thanks a lot....

But I would also like to know why the above code is Alerting me with the "Window" Object instead of Employee Object.

What i assume is that when "new Employee()" is called, it does following things:

1. Create a separate memory block for it.
2. Assign properties to Object
3. Assign this to object
4. Return this

So the code, "new Employee()" is called from the global scope. While the global scope is executing the specified steps, it encounters a function "calculateBonus". The function is now executed under the global context since the new object is still not created.

So when this function is executed from the global scope, therefore the context of function execution becomes "global" and therefore "alert(this)" gives "window" object.

Please tell me if my assumption is correct or not. Or there is some problem in understanding the scope resolution for this function.

Regards,
Mayank Gupta
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900