JavaScript function binding (this keyword) is lost after assignment - javascript

this is one of most mystery feature in JavaScript, after assigning the object method to other variable, the binding (this keyword) is lost
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
john.greet("Mark"); // Hi Mark, my name is John
var fx = john.greet;
fx("Mark"); // Hi Mark, my name is
my question is:
1) what is happening behind the assignment? var fx = john.greet;
is this copy by value or copy by reference?
fx and john.greet point to two diferent function, right?
2) since fx is a global method, the scope chain contains only global object. what is the value of this property in Variable object?

john.greet("Mark") actually calls a function. When you do var fx = john.greet;, you're getting a reference to the function. So when you call it, this is not bound to john. What you're actually doing is window.fx("Mark") and so this is the window object. You were on the right track when you said that it was in the global context. In this particular instance, the global object is window, and so fx is actually window.fx.
When you have a function reference you should use call or apply if you want to set the value of this. Try doing this:
fx.call(john, "Mark");
The first argument in call or apply is the value used for this in the context of the function call.
EDIT
Some people mentioned that the real issue here might be confusion surrounding an object literal vs. an instance of an object. You're creating an object literal which also behaves kind of like a singleton. You cannot create a new instance of that object. In this case john is a reference to that object literal. In that context, this in the function greet refers to the object literal itself. Hence when you call john.greet("Mark"), this is bound to john.
When you grab a reference to john.greet just by itself and assigning it to a global variable, you're essentially doing this:
var fx = function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
In this scenario, this is window, because fx is basically window.fx (since the global object here is window. Assuming this code was wrapped inside another function, then the global object would refer to that function.
If you want to create multiple instances of an object, you can do something like this:
var Person = function(name) {
var self = this; //maintains a reference to the instance
this.name = name;
this.greet = function(name) {
alert("Hi " + name + ", my name is " + self.name);
}
}
var john = new Person("John");
john.greet("Mark"); // alerts "Hi Mark, my name is John"
var fx = john.greet;
fx("Mark"); // also alerts "Hi Mark, my name is John"
Here, the self variable (which is local to the function) maintains a reference to the actual instance because you're binding it to this when you create the object.
There are many best practices associated with OOP in Javascript. You can Google and find out (there are many links). I recommend reading stuff from Douglas Crockford especially.

1) fx and john.greet are referring to the same function object, the assignment operation for objects, works by reference.
For primitive values, like String, Number, Boolean undefined or null, a copy of the value will be made.
2) The this value refers to the global object.
The this value is not a property of the Variable Object and it has nothing to do with the scope chain, is a special reserved word, and it is determined implicitly when a function is called (you can also set it explicitly via call or apply).
JavaScript internally handles a Reference type, which consists of two components, the base object and the property name, when a function is invoked, the this value is determined implicitly by getting the base object (by the internal GetValue operation).
And finally, the last case where this is set implicitly is when you invoke a function with the new operator, the this keyword will refer to a newly created object.
So in brief, here is how this works implicitly:
1- When a function is called as a method (the function is invoked as member of an object):
obj.method(); // 'this' inside method will refer to obj
2- A normal function call:
myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
3- When the new operator is used:
var obj = new MyObj(); // 'this' will refer to a newly created object.

As I understand it, you're only assigning that method to the variable "fx." The context of the john object doesn't come along with it.
Off the top of my head, "this" in the context of fx will refer to the global object, which in the context of a browser is (I believe) equivalent to your window object.
(editing to clarify global object. Sort of)

Because you're only setting fx to the greet method and not the entire john object, it has no concept of it's parent and becomes globally scoped. So in essence, it's passing by value in that in only copies the method.
Since the function is now globally scoped, "this" becomes the Window object.
If you instead set fx to john, you get what's expected.
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
john.greet("Mark"); // Hi Mark, my name is John
var fx = john;
fx.greet("Mark"); // Hi Mark, my name is John

inspired by #Vivin Paliath answer, actually I come out something new. As to me, I always try my best to make javascript programming the same way as java, especially in OOP.
So my suggestion is to avoid using this as possible as we can , when we first do
var self = this;
we should use self instead of this in all function (prototype function, whatsoever), but if we write something like this:
function MyObject = {
var self = this;
};
MyObject.prototype = {
method1 = function(data){
self.data = data;
}
}
This is not gonna work, because prototype is an object in MyObject, It can not access private member self owned by MyObject. My solution for this is simple:
function MyObject = {
var self = this;
MyObject.prototype.method1 = function(data){
self.data = data;
};
}
This takes the advantage of prototype's efficiency and also we do not have to care about all the this issues. Though we gonna type a lot of MyObject.prototype.xxxx thing.
If this helpful to your guys, please give me some thumb up, so I can gather 15 reputation to thumb up others, thanks.

Related

Using This in Javascript

I have read over some rules to determine what the value of this is in different scenarios in Javascript. All was well till the example below threw me off.
function Person(name){
this.name = name; //this is the object when function used as constructor (as expected)
this.changeName = someFunction(); // produces error
function someFunction(){
this.nickName = this.name+"by"; //this is now the global object and not the instance, thus the name property does not exist.
}
}
var a = new Person ('bob'); //error due to the function in changeName property.
From what I understood, the this variable takes up the value of the invoking object when called through dot notation or takes up the value of the newly constructed function when used with the new key word.
Can someone explain why the this statement in the function above is the global objet and not the newly instantiated object?
Can someone explain why the this statement in the function above is the global objet and not the newly instantiated object?
Because when you call a(n unbound) function as func(), this will refer to the global object (or undefined if the function is in strict mode).
Every function (except arrow functions) has its own this value. So the fact that you are calling Person as new Person() and that this inside Person refers to a new object, doesn't have any impact on the this value in someFunction. It only matters how you can someFunction.
You could call someFunction and explicitly set its this value via .call:
this.changeName = someFunction.call(this);
See also: How to access the correct `this` inside a callback?
The this within someFunction() will reference a global object, because it's inside a function call. See a fuller, much more complete explanation at How does "this" keyword work within a function?
If you wish to solve the issue, alias this inside the parent.
function Person(name){
var self = this; // Store a reference to the current instance
self.name = name;
self.changeName = someFunction(); // Odd that you'd capture the return value of a setter, ...
function someFunction(){
self.nickName = self.name+"by"; //self references the instance, creating the property.
}
}

JavaScript constructor function, prototype attach method, and 'this'

I'm working through CodeAcademy JS excercises and have a question about this example:
//Animal class
function Animal(name) {
this.name = name;
}
//Attach sayName method to Animal class
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
//create an animal object instance
var dog = new Animal('Barker');
//invoke a method attached to the prototype from the object instance
dog.sayName();
My understanding of this code is:
JS creates a new Animal object instance that var dog points to as a result of the use of the new keyword before the call to function Animal() - a function constructor
The prototype of the var dog object has the sayName() method attached to it in the line: Animal.prototype.sayName = function()
Because sayName() was attached to the class prototype, the method is now available to any objects created from the Animal class through use of the new Animal() function constructor
Is this a correct understanding of what is happening with this code?
Also, I'm trying to understand how this points to the Animal object in this.name:
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
Doesn't Animal.prototype point to an actual object: the prototype object of this Animal object instance? If so, shouldn't this in this.name point to Animal.prototype, since sayName() is actually being invoked from Animal.prototype?
My understanding of the context for this is that this always points to the object that invokes the function. However, in this case, when dog.sayName() is invoked, this points to Animal, which is how this.name equals 'Barker' when it is logged to the console.
I'm guessing that either I am misunderstanding that Animal.prototype points to a prototype object, or that JS is doing something "behind the scenes" to associate dog.sayName() to this in the context of attaching a method to the prototype.
Multiple questions here in this little example, but getting a grasp on exactly what is happening here will really help my understanding of these fundamental concepts.
[points 1-3]
Is this a correct understanding of what is happening with this code?
Yes, sounds like you understand it.
Doesn't Animal.prototype point to an actual object: the prototype object of this Animal object instance?
Yes, the prototype object is an Object instance.
If so, shouldn't this in this.name point to Animal.prototype, since sayName() is actually being invoked from Animal.prototype?
No, because you called it as a method of dog.
dog.sayName();
If you called it like this, then yes, this would have referenced Animal.protoype.
Animal.protoype.sayName();
But that wouldn't be very useful.
My understanding of the context for this is that this always points to the object that invokes the function.
Not quite. For the most part this refers to the object the method was called on, not the object it is a property of. A method can actually be a property of multiple objects, so this dynamically points to the object it was called as a method of.
Of course, this can refer to other things in other contexts, such as when not called as a method, or in a bound function using .bind.
You misunderstood this. The value of this is not set when you create the function, it's an additional argument. Each time you call a function, the this value can change.
In case of methods, the this value is set to the base object. For example,
dog.sayName(); // `this` is `dog`
({sayName: dog.sayName}).sayName(); // `this` is this new object
(0,dog.sayName)(); // `this` is undefined or the global object
this has two distinct characteristics in Javascript that cause a lot of confusion:
it's the only dynamically scoped built-in feature of the language
it's treated as an implicit parameter
Lexical scope
var i = 0;
const inc = () => i + 1;
const inc2 = x => {
var i = x;
return inc();
};
inc2(100); // 1
Dynamic scope
var o = {
i: 0,
inc: function () { return this.i + 1 }
};
var p = {
i: 100,
inc2: o.inc
};
p.inc2(); // 101
this is dynamically scoped, because it's set through the invocation context.
Implicit parameter
Instead of passing this explicitly as a formal parameter to methods, it's treated implicitly. Hence you need to use call/apply to set different values (namely objects) for this:
// Note that s and t are implicitly converted to objects
const split = (o, x) => o.split(x);
let s = "1,2,3", t = "4,5,6";
// objects are passed explicitly as normal arguments
split(s, ","); // ["1", "2", "3"]
split(t, ","); // ["4", "5", "6"]
// objects (or this) are provided implicitly
s.split(","); // ["1", "2", "3"]
s.split.call(t, ",") // ["4", "5", "6"]
Imagine this as the receiving object of a method, which must be passed as the first parameter.

javascript prototypes vs this

I'm trying to get a better grip on the what and whys of javascript classes. Specifically, I'm trying to understand the differences between assigning a method to a prototype vs using a this.methodName = function ... statement in a constructor. So, I did an experiment:
function CThis(){
this.method= function() {
console.log("method of ",this);
};
}
function CProto(){
}
CProto.prototype.method = function() {
console.log("method of ",this);
};
window.onload = function(){
ct = new CThis();
ct.method();
cp = new CProto();
cp.method();
};
My hypotheses was that the two would behave the same way, but I learned something. This was the output:
"method of " Object { method: CThis/this.method() } oop.js:3:4
"method of " Object { } oop.js:11:2
Using this.method in the constructor actually gave me the behavior I would want from an instance of a class in a typical oop program: ie, "this" was referring to the class instance. Using the prototype method, it seems that this referred to an empty object.
I guess my question here is threefold:
What is the "this" referring to inside CProto.prototype.method?
What's the rest of the story with respect to assigning a function
to this inside a constructor vs using the object's prototype?
Seemingly, the version using this. inside a constructor is the one
doing what I'd want to do (namely, be able to access the variables
inside an instance of a class). Given that, why do the javascript
oop tutorials talk about prototypes so much?
Thanks in advance!
---EDIT---
I thought a little more about this and realized that perhaps it would be worthwhile to extend the example beyond the single method and try to see what variables where accessible.
function CThis(){
this.localthis = "I'm this.localthis";
var localvar = "I'm localvar";
this.method= function() {
console.log("method of ",this);
console.log("value of this.localthis:", this.localthis);
console.log("value of localvar with this.:", this.localvar);
console.log("value of localvar without this.:", localvar);
};
}
function CProto(){
this.localthis = "I'm this.localthis";
var localvar = "I'm localvar";
}
CProto.prototype.method = function() {
console.log("method of ",this);
console.log("value of this.localthis:", this.localthis);
console.log("value of localvar with this.:", this.localvar);
console.log("value of localvar without this.:", localvar);
};
window.onload = function(){
ct = new CThis();
ct.method();
cp = new CProto();
cp.method();
};
And the new output:
method of " Object { localthis: "I'm this.localthis", method: CThis/this.method() } oop.js:5:4
"value of this.localthis:" "I'm this.localthis" oop.js:6:4
"value of localvar with this.:" undefined oop.js:7:4
"value of localvar without this.:" "I'm localvar" oop.js:8:4
"method of " Object { localthis: "I'm this.localthis" } oop.js:18:2
"value of this.localthis:" "I'm this.localthis" oop.js:19:2
"value of localvar with this.:" undefined oop.js:20:2
ReferenceError: localvar is not defined
So there are definitely differences with respect to variable scope (in the this.method, I can access var variables from inside the constructor).
In the first case each instance you create has its own copy of the method, and therefore when you print the object out it's visible. The JS engine also likely has to perform the compilation step on this function each time the constructor is called.
In the second case, none of the instances you create have any properties at all. Instead, when you call the method, the js engine walks up the prototype chain looking for a property of the right name. It looks at cp.__proto__ and finds a pointer to the object which you're referring to as CProto.prototype, which does have a property called "method" which it can call.
As an additional test, add a real instance variable to your classes. Add this.foo = 42; to both constructors, then see what you get.
Firstly, javascript OO is prototypical, so it's not exactly like Class-based OO. You seem to have grasped the essential parts.
The way Prototypical inheritance works is a bit like a backwards data-tree: if you don't find the property on the object itself, look at it's prototype, if it's not on it's prototype, look at it's prototype's prototype and so forth until there is no prototype left.
1. What is the "this" referring to inside CProto.prototype.method?
when calling a METHOD, this always refers to the contextual object (i.e. the object used to call the method).
obj1.hello() // this === obj1
obj2.hello() // this === obj2
Object.getPrototypeOf(obj1).hello() // this is now global since you didn't use a contextual object.
obj1.hello.call(obj2) // this === obj2, because we forced a context change
2. What's the rest of the story with respect to assigning a function to this inside a constructor vs using the object's prototype?
Assigning to the prototype makes all instances of the prototype inherit that method.
Assigning within the constructor means only the instance has the method.
Otherwise, it's essentially the same. The only advantage a instance method will have is access to the instance's private context (closure).
When assigning within the constructor, the object itself is the "owner" of the method. This changes how Object.key() and for in will work. When it's on the Prototype, the prototype object is the "owner" so your instance objects don't have the method as an own property. It may seem trivial, but this is an important distinction, especially when looping/cycling through object properties.
When you're assigning via the prototype there is only one instance of your method (it's on the prototype). When you're assigning via the constructor, you're creating a new context and a new function for each instance. While insignificant, there is a performance difference.
3.
Pretty much explained with the two above answers.

How does Javascript evaluate "this"?

I am trying to understand some basic javascript .
I have the following snippet. We have the name variable which in both cases are referenced over getName Method.
First alert outputs HocusPocus, while the second one outputs GeorgeThomas. But I do not understand how this refers to name in this case
var name = 'Gerorge Thomas';
var obj = {
name: 'Cinderella',
value: {
name: 'HocusPocus',
getName: function() {
return this.name;
}
}
};
alert( obj.value.getName() );
var testing = obj.value.getName;
alert(testing());
To understand this issue, you have to understand how Javascript sets the value of this in a function call.
There's a summary of all the methods here: When you pass 'this' as an argument
For your particular case, when you do this:
var testing = obj.value.getName;
You now have a reference to the getName function. You no longer have any connection at all to obj.value. So, test() just calls getName as an ordinary function. In Javascript when an ordinary function call is made, then the value of this will be either the global object (window in a browser) or in strict mode, it will be undefined.
In your case, this becomes the window object so this.name is window.name which points to the global variable name and thus you get the result 'Gerorge Thomas'.
In fact, if you run your code in strict mode, it will cause an error which is, in fact, one of the benefits of strict mode that it points out accidental errors like this.
On the other hand, if you execute a function with the form of obj.method(), then this is set to be obj. So, when you do:
obj.value.getName()
that is equivalent to:
var o = obj.value;
o.getName()
which is the obj.method() form of calling a function which will set the this pointer to be the object, which in this case is obj.value.
It is possible to work around this issue in a couple of ways. Here's an example of working around it using .bind().
var name = 'Gerorge Thomas';
var obj = {
name: 'Cinderella',
value: {
name: 'HocusPocus',
getName: function() {
return this.name;
}
}
};
document.write( obj.value.getName() + "<br>");
var testing = obj.value.getName.bind(obj.value);
document.write(testing());
Well it only needs some reflection, let's analyse it:
In the first alert we are calling the getName() method of the
obj.value object so it returns obj.value.name which is
"HocusPocus".
alert( obj.value.getName() ); we call this.name where this refers to obj.value so name is HocusPocus
But in the second alert we are creating a new function testing()
with the body of the getName() method, so it will be attached to
the global window object and if we call it we will get the global
name value wich is 'Gerorge Thomas'.
alert(testing()); we are dealing with this.name where this refers to the global scope so name is 'Cinderella'.
First, you're calling a method from inside the obj object. The 2nd time, you're making a copy of the function (not really, it's just a reference) in the global scope. So you could also write window.testing() for the 2nd call. I think that makes it clear.

When I assign prototype to function I get undesired output

Please follow the code below,
var fn79 = function(){
var Student = function(_name){
this.name = _name;
};
Student.prototype = function(){
print("Inside Prototype function");
};
//Student.prototype = {}
var obj1 = new Student("Ricky");
Student.prototype.lastName = "Gonzales";
var obj2 = new Student("Jacky");
print(obj1.name+" - "+obj1.lastName);
print(obj2.name+" - "+obj2.lastName);
};
fn79();
The output I get is
D:\Rahul Shivsharan\MyPractise\JavaScriptCommandLine>java -jar js-14.jar prac.js
- Gonzales
- Gonzales
D:\Rahul Shivsharan\MyPractise\JavaScriptCommandLine>
From above output you can see I am not able to print "name" property of objects.
now if I change the the code to as below,
var fn79 = function(){
var Student = function(_name){
this.name = _name;
};
/*
Student.prototype = function(){
print("Inside Prototype function");
};
*/
Student.prototype = {}
var obj1 = new Student("Ricky");
Student.prototype.lastName = "Gonzales";
var obj2 = new Student("Jacky");
print(obj1.name+" - "+obj1.lastName);
print(obj2.name+" - "+obj2.lastName);
};
fn79();
I get the desired output as
D:\Rahul Shivsharan\MyPractise\JavaScriptCommandLine>java -jar js-14.jar prac.js
Ricky - Gonzales
Jacky - Gonzales
D:\Rahul Shivsharan\MyPractise\JavaScriptCommandLine>
Why my First example was not working properly.
Function is an object itself in javascript.
What I thought is,
Student.prototype = function(){
print("Inside Prototype function");
}
Student's prototype is pointing to function which itself is an object.
So why "name" is not getting printed in my first case, and how prototype assigning to function effects it.
The problem with functions is that they do have a non-writable .name property. This non-writability even affects the objects that inherit from the function, in your case the Student instances, so the assignment fails:
var Student = function(name){
console.log(this.name);
this.name = name;
console.log(this.name);
};
Student.prototype = function ProtoName() {};
console.log(Student.prototype.name);
new Student("test");
You'll just see the string "ProtoName" thrice.
You can use strict mode to make it more obvious that the .name = fails:
var Student = function(name){
"use strict";
this.name = name;
};
Student.prototype = function ProtoName() {};
new Student("test");
You'll get an Error: Invalid assignment in strict mode.
You can work around the non-writability by creating the .name property on the Student instance using Object.defineProperty instead of the simple assignment, but really you just should not use a function object as a prototype.
You seem to have a misunderstanding of what prototypes are and how you should use them. I will refactor your code and tell you why this works the way it works, as well as the general consensus for how to use them:
You declare a function - this is called the Constructor function. It will construct all the variables etc..
function Student(firstname, lastname){
this.firstname = firstname;
this.lastname = lastname;
}
Your prototype is an object with keys and values. This is simply because your prototype will not exist on actual products, it will act as if it's right there on the element (and not in element.prototype). We'll get to that, but for now you should keep in mind that variables are best declared inside your constructor function above, and methods are best in the prototype. You can mix them, but it's an easy divide and it keeps your code clear.
Student.prototype = {
showName: function(){ return this.firstname + ' ' + this.lastname; }
};
Now when we construct an instance of student, we can use the method showName as such:
var gonzales = new Student('Johny','Gonzales');
console.log(gonzales.showName()); // 'Johny Gonzales'
Also note that we do not mention the prototype on a consturcted object. It is still 'available' in __proto__ as it's inherited etc... But from a normal point of view this does not matter.
Variables are also directly accessible, using by simple using dot notation. By the way, keep in mind that variables and methods share the same namespace!
console.log(gonzales.firstname); // Johny
You cannot set the prototype as a function itself (unless it is a self executing function that returns an object). Functions in javascript, although considered objects, are different beasts with their own magic - do not treat them like objects as they will not treat it kindly. Don't try to do this, as it can break some Javascript inheritance and will create countless bugs you cannot squash.
For more details and accurate naming, see this article: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Custom_objects
While it is true that an function in JS in the end is also an Object, it's not the same way the other way around, since that would mean every Object is also a function.
The prototype Object holds all the functions the prototype has. This is VERY important for Object inheritance and the like.
If you think back to memory schema's it's like this:
{
hi : function hi(){}, // pointer to the function 'hi'
bye : function bye(){}, // pointer to function 'bye'
data : { planet : 'earth' } // pointer to an Object with a pointer to a String which contains 'earth'
}
If you overwrite the Object with a function, it all dies.
Mainly since JS 'knows' that a the an Objects prototype is supposed to hold functions or other objects, and does not 'execute' the prototype Object itself.
So basically, it's more like an index used by JS to find stuff that you may or may not need in an Class' instance
When you set the prototype of the Student object like this :
Student.prototype = function(){
print("Inside Prototype function");
};
The prototype of Student will be this simple function as #somethinghere pointed out, (instead of containing the function constructor and the object __proto__), so all the properties and the functions of Student will be removed. This is why the property name will be removed.
And when you add the second property lastname to Student:
Student.prototype.lastName = "Gonzales";
The prototype of Student will now has the property lastname.
And as #somethinghere pointed out :
every instance of Student will now share that last name
More informations about the prototype of an Object

Categories