compare Javascript scope - javascript

The following segment:
var obj = {
name:'Tom',
sayHello:function() {
console.log("hello," + this.name);
}
}
var name = 'Kevin';
var method = obj.sayHello;
method();
will get the output:
hello,undefined
but, if change var name = 'Kevin'; to name = 'Kevin'; The output will be hello,Kevin. Why they are different?

There are two halves to the answer:
When you use var method = obj.sayHello;, you are decoupling the function from obj. When you invoke the a method without giving it an explicit object, (ie, method() instead of obj.sayHello()), JavaScript sets this to the global object, window.
When you define a variable using var name = 'Kevin', you're creating a local variable with function scope. When you define a variable using name = 'Kevin', you're creating a global variable, attached to the global object, window. This is identical to writing window.name = 'Kevin'.
These two things combine to mean that, inside sayHello, this is window and this.name is Kevin.
To solve this, you need to use bind, which returns a copy of your method with its context fixed to the object provided as an argument to bind:
var method = obj.sayHello;
new_method = method.bind(obj);
new_method(); // hello, Tom

sayHello:function() {
console.log("hello," + this.name);
}
this in this function refers to the global object. When you change var name = 'Kevin'; to name = 'Kevin';, name variable is set in the global object. Since, name is set in global and this is global, this.name refers to Kevin and it prints hello,Kevin.

The this keyword can be tricky to get.
If you call obj.sayHello, the this keyword will refer to obj.
When you write method = obj.sayHello that the same thing that writing:
window.method = function() { console.log("hello," + this.name); }
The this keyword will now refer to window.
That's why when you reference a variable having name for its name, you write window.name which can be found by your function.

How you call a function determines the value of this in the method. In your way of calling:
var method = obj.sayHello;
method();
You are losing the obj reference to this inside of your invocation of sayHello() so this is set to the global object or undefined, not set to obj. Thus, the errors you are getting.
When you do this:
var method = obj.sayHello;
All, it does it put a reference to the sayHello function in the method variable. Nowhere is anything to do with obj stored in method. So, when you then call method(), there is no object reference at all so instead of obj.sayHello() which causes this to be set to obj, you're just calling sayHello() all by itself which does not set the value of this to obj.
There are multiple ways to fix it.
1) Helper Function.
var method = function() {obj.sayHello()};
method();
2) Use .bind()
Here .bind() will create a helper function for you.
var method = obj.sayHello.bind(obj);
method();
3) Change sayHello() method
You can change the sayHello() method so it doesn't use the this pointer (which works fine if it is a singleton object, but not if there are multiple instances):
sayHello:function() {
console.log("hello," + obj.name);
}

Related

Javascript "this" scope giving different result depending on the way it is called

All,
This is the code:
var Person = function (name) {
this.name = name;
this.printName = function(){
console.log("My name is " + this.name);
}
};
var p = new Person("Steve");
var funcRef = p["printName"];
p.printName();//Works
p["printName"]();//Works
funcRef();//returns incorrect value
Find a working example here: http://plnkr.co/edit/57LS6oXPfqccAWf6uqQV?p=preview
My question is what's the difference between the last two? I'm accessing the object method in the same way, the only difference is the way it's being called.
Why does it return a difference result?
First time I have come across this in javascript. I understand it's in a difference scope but i don't know how it got decoupled from the object which is what I'd like to understand.
Thanks
Steve
javascript bind the this keyword when you call the function on the object directly.
With test.fn(), this will be test inside fn. Same with test['fn'](). But if you do var fn = test.fn; fn(), this will be the global root (window in a browser) inside fn.
You can force the this inside a function like this : var fn = test.fn.bind(test);
More informations here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Case1 :
'this' always takes the context of the object with respect to which its called.
In p.printName() the context is p therefore 'this' references the Person object that 'p' refers to.
Case2:
But, when you direct 'funcRef' to p's method it loses this context and 'this' references the global object.
The global object can be different depending on your js environment (like the browser context or node and so on).
That is why you see different results.
As other answer say, this is bound when you call the function. A common way to keep the reference to the object is to use something like this:
var Person = function (name) {
var self = this; // Keep a reference to this object for later use
self.name = name;
self.printName = function(){
console.log("My name is " + self.name);
}
};
How this scope behaves is already explained by above answers, here is best practice for 'this' usages, use 'this' as a new variable called 'self', see below code, this way you have better control and less error due to wrong usages of this scope.
var Person = function (name) {
var self=this;
self.name = name;
self.printName = function(){
console.log("My name is " + self.name);
}
};

Why is "this" necessary when define arguments?

function Person(firstName, lastName, age)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
var family = {};
family.mother = new Person("Susan", "Doyle", 32);
…
Do we have to use "this" here? and why?
function …
{
firstName = firstName;
lastName = lastName;
age = age;
}
I wonder if this question is too simple …
in javascript the this word is a reference to the object of invocation.
So if we have a global function
function () {console.log(this);} // Window
We get the global object or window.
if we have a deeper function in an object
var obj = {f: function (){console.log(this);}};
obj.f(); // Object {f: function} we get the object that wraps the function.
This rule is broken if we use the apply invocation pattern
obj.f.apply(window); // window is now bound to this.
In your example if you were to just call
Person(); // in global scope
you would effectively be assigning
window.firstName = // ...
window.lastName = // ...
window.age = //...
Because the this keyword is bound to the window object when called from global scope
You basically created a Constructor that should be called with the new operator. The new operator wraps your function with one that creates an object and calls your function using the apply method with the object as the this parameter.
var bob = Person("bob"); // bob is undefined but you changed the window object
var sue = new Person("sue"); // sue is an object like you expect.
Examine your code
var family = {}; // make an object
family.mother = new Person("Susan", "Doyle", 32);
because you used new before you function executes js makes a new object for you and uses the apply pattern to that object. This is what happens under the hood
family.mother = {};
Person.apply(family.mother, ["Susan", "Doyle", 32]);
Here this is required to referring the current object's value.
If you don't use the this keyword the local variables get shadowed down by function parameter.
In your Person() function scope - the function parameter get higher priority than the local variable. That means inside your Person() function the by default the firstName is considered as the function parameter even though there is some field by the same name. In this case to reference the field the this keyword is used.
This is the correct way to define an object constructor. you can get reference here
The this Keyword
In JavaScript, the thing called this, is the object that "owns" the JavaScript code.
The value of this, when used in a function, is the object that "owns" the function.
The value of this, when used in an object, is the object itself.
The this keyword in an object constructor does not have a value. It is only a substitute for the new object.
The value of this will become the new object when the constructor is used to create an object.
Note that this is not a variable. It is a keyword. You cannot change the value of this.

JavaScript function members differences

I'm still confused about this part of the closure although I read about it a lot (also here in the site).
Took the code from here:
http://www.crockford.com/javascript/private.html
So what is the different between this:
function Container(param) {
this.member = param;
}
...And this -
function Container(param) {
var member = param;
// and also in case it's without "var", I.e. global
}
Please explain what happens when you're creating the obj for each case -
var myContainer = new Container('abc');
Also -
What are the access differences for the parameter from the object? And can you give example for a function as a parameter and a returning function?
Thanks a lot!
Here is my opinion:
When you use the new to create an object through function,the variable initial by var is local variable:
function Test(){
var name = "John";
this.getName = function(){
return name;
}
}
var obj1 = new Test();
console.log(obj1.name); //undefined
console.log(obj1.getName()); //John
That means you can't read the variable directly outside the function.This is like private variable in Java or c++;
but when you use this.name = "John", this is a different situation:
function Test2(){
this.name = "John";
}
var obj2 = new Test2();
console.log(obj2.name) //"John"
you can read the variable directly, this is like "public" variable in java or c++.
Hope this can work for you. : )
In function Test, when we declare a variable obj1 with new Test. It have been created through the contructor function which is called "Test".
This process is like we call a function in a normal way. Of course that make a local variable "name". When we decleared a function expression which is called "this.getName", that just mean an expression to function "Test".
But when we call the "new Test".It return a object which have a key-value call "getName:function{}". When we call "obj1.getName", it return the variable "name". But it cannot find the getName's local variable "name", so it will search its parent's scope to find if there is a variable "name",it will not stop until we get it or just return "undefined". That make an "quote" to keep the variable "name" in memory, but we just can get it through the function "getName".
For all of this, we make a private variable in our function "Test". : ) Hope this can help.

Why do you need to use this.property=property in objects?

Why do you need to use this.property = property in objects?
Is it used to define the property to the "outside world" of the object?
function Person(property) {
this.property = property;
}
var john = new Person(true);
If you didn't, john.property would be undefined.
The this keyword is used to refer to the owner of the function executed:
http://www.quirksmode.org/js/this.html
As said, you need it to define the john.property, because the property variable passed to the function will expire once the function is executed.

Why do I have to use "this" to access in inner property of a function

What is the difference between
function person(first_name, last_name) {
this.first = first_name
this.last = last_name
}
and this:
function person(first_name, last_name) {
var first = first_name
var last = last_name
}
Why only the first one makes person.first & person.last accessible outside the function?
The this keyword within a function is called the invocation context.
1) If you define your function as a member of an object (a method):
myObject.someMethod = function() { this.x = 2; };
then the invocation context, this, is the object to which the method is being added, myObject. So after calling myObject.someMethod(); above, myObject.x is then 2. The member x is undefined until you call the method, unless you defined it before.
2) If you use your function as a constructor with the new keyword, then this refers to the new object that is being created:
function MyX() { this.x = 3; };
var myX = new MyX();
You'll then have property myX.x set to 3.
Note that I called my constructor MyX(), not myX(). You should call yours Person(), not person(). It's just a convention, but it is useful to indicate that a function is meant to be used as a constructor.
3) Finally, if you use this within a function that you call as neither a method nor a constructor, then this refers to the global object (document or, equivalently, window). Note however that if you are using javascript in strict mode (which you should do), this is undefined in such a situation, which means that you basically cannot use this in a function that is not a method or a constructor.
Your specific question refers to case 2), the constructor. this.x = 3 in the constructor just sets property x of the newly created object. After some object myX is created, you can then access and modify x externally as any other object property using myX.x.
when you write constructor function ( using new) - you add properties using this.XXX
then you do :
var p = new Person('s','d');
and then you have access to p.first etc.
in the second example :
youre not creating any properties..
youre only creating private variables.
so you cant access them...
By using this.something you're saying that THIS is an object and something is his property.
By using var, you're saying that it's just a variable and not a property.
More information about variable vs property:
http://javascriptweblog.wordpress.com/2010/08/09/variables-vs-properties-in-javascript/
Because of function scope.
A variable lifetime is between the curly braces of the function. The this keyword allows to access the function properties outside of it.
Definitely take a look at this link: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope
'var' keyword make a variable scoped. In the last example var first and var last create variable accessible only in the scope of the function. You can see this as a local variable in a constructor.
when in javascript you declare a variable as
var variable
it only exists inside the method where you declared it. If you want a variable to be accessible for everyone (that is, global) it has to be declared without the 'var' part
You do not necessarily have to use this. It'd also work fine if you've got a structure like this:
Person = function(first_name, last_name) {
var first, last;
create(first_name, last_name);
function create(first_name, last_name) {
first = first_name
last = last_name
}
return {
firstName: first,
lastName: last
}
}

Categories

Resources