Changing 'this' in javascript method calls? - javascript

Follow up question to this one, call javascript object method from html. I'm debugging this in Firebug.
function Fred() {
this.a = 1;
function foo() {
if (a == 1) {
a++;
}
var e = 0;
}
this.bar = function () {
var a = 3;
foo();
};
}
From an HTML file, I create a new instance of Fred and invoke bar(). In Firebug, on the call to bar(), I can see in the Watch view this is my Fred instance. When bar() invokes foo(), this changes to an instance of Window. I would have expected this to remain the same.
Maybe more remedial training on closures.

In JavaScript, if you call a function, the fact where this points to is depending on the context of the call.
Function invocation pattern
If you call a function as a function, i.e.:
foo();
then this will refer to the global context, which in the browser means the window object.
Method invocation pattern
If instead you call a function like a method, i.e.:
x.foo();
then this will refer to the object where you called the function on, i.e. x.
Call / apply invocation pattern
If you want to call a function as a function, and change what this refers to you can use the call or the apply function, such as
foo.call(x);
foo.apply(x);
Both do the same thing: Call foo as if it was called as a method on x. The difference between them is when you want to hand over parameters: call requires you to specify them as a comma-separated list, while apply lets you hand over an array:
foo.call(x, p1, p2, p3, ...);
foo.apply(x, [ p1, p2, p3, ... ]);
Constructor invocation pattern
Just for the sake of completeness, there's even a fourth option of what this may be: If you call a function as a constructor, this points to the newly created object:
new foo();
To make this obvious to everyone, in JavaScript you have the best practice to start the name of a function that acts as a constructor with an upper-case letter, i.e.:
new Foo();
Nevertheless, the effect stays the same.

Use .call() or .apply()
The first paramater states the context in which the following function will be called.
e.g.
this.bar = function () {
var a = 3;
foo.call(this);
};

Related

Nested .bind not working as expected

Unfortunately .bind has been giving me grief when creating more complex closures.
I am quite interested in why .bind seems to work differently once you nest functions.
For example :
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return nested_t;
}
return nested_t();
}
//CASE ONE
alert(t());
// alerts the whole function t instead of nested_t
//CASE TWO
aleft(t.call(t));
// alerts the global object (window)
In both cases I was expecting a behavior like this:
function t(){
var nested_t = function nested_t(){
return this;
};
return nested_t.call(nested_t);
}
alert(t.call(t));
If someone could explain the behavior of .bind in the first (and/or) second case it would be much appreciated!
So, i'm not entirely reproducing your issue here (both cases return the global object), but i'll try and explain the code as i see it.
function t(){
t = t.bind({}); //correctly assigns *this* to t
function nested_t(){
nested_t = nested_t.bind({}); // fails to assign *this* to nested_t
return this;
}
return nested_t();
}
//CASE ONE
alert(t());
Let's take it step by step.
First, the function t() is defined. Then, upon call, it gets overwritten with a clean context. However, i don't see any usage of this context.
Now, a nested function (nested_t) is defined. Upon call, it is overwritten with a clean context. It then returns the context it had when it was called.
Back to t(). You then return the result of nested_t(), not nested_t itself. In the original function call, nested_t is still being called with global context.
Therefore, when you run t(), it returns the global object.
How your code works
It's very unclear, what your code is trying to do. You can find the documentation for .bind() here. It looks like you might be somehow misunderstanding what this is and how to use it. Anyway, what happens when you run your code is this:
A t function is created in global scope.
[case one] The t function is called.
Global scope t is replaced with a new value (original t bound to a specific context - anonymous empty object), which doesn't affect the current call in any way. Also, while the global t is overwritten, the local t is behaving as read-only. You can check it out by trying the following code: (function foo () { return (function bar () { bar = window.bar = 'baz'; return bar; })(); })() and comparing return value with window.bar.
The same thing happens with nested_t in the nested context (instead of global context).
Result of nested_t call is returned. nested_t returns the context it was called with, which was window, as no context was specified. Specifically, it was not called with an empty object context, because the .bind() inside didn't affect the call itself.
[case two] The exact same thing happens once again. Now you're just calling t with itself as context. Since t doesn't use its context (this) anywhere in its code, nothing really changes.
What your misconceptions might be
Basically, you're mixing up two things - function instance and function call context. A function is a "first-class citizen" in JavaScript - it's an object and you can assign values to its properties.
function foo () {
foo.property = 'value';
}
foo(); // foo.property is assigned a value
This has nothing to do with function call context. When you call a function a context is assigned to that call, which can be accessed using this (inside function body)
function foo () {
this.property = 'value';
}
var object = {};
foo.call(object); // object.property is assigned a value
When you use .bind(), you just create a new function with the same code, that is locked to a specific context.
function foo () {
this.property = 'value';
}
var fixedContext = {},
object = {};
bar = foo.bind(fixedContext);
foo.call(object); // fixedContext.property is set instead of object.property
But in this case, there are also function instances foo and bar, which can also be assigned properties, and which have nothing to do with contexts of calls of those functions.
Let's look at how bind works. First, one level of nesting:
var foo = function() { return this.x; };
alert(foo()); // undefined
alert(foo.bind({x: 42})()); // 42
Now we can add the next level of nesting:
var bar = function() { return foo.bind(this)(); };
alert(bar()); // undefined
alert(bar.bind({x: 42})());
We pass our this context to foo with - guess what? - bind. There is nothing different about the way bind works between scopes. The only difference is that we've already bound this within bar, and so the body of bar is free to re-bind this within foo.
As a couple of commenters have noted, functions that overwrite themselves are a huge code smell. There is no reason to do this; you can bind context to your functions when you call them.
I highly, highly recommend reading the documentation on bind, and trying to understand it to the point where you can write a basic version of Function.prototype.bind from scratch.

Verifying my understanding of the scope chain

(Question 1)
In Flanagan's JS Definitive Guide, he defines the Function method bind() in case it's not available (wasn't available n ECMAScript 3).
It looks like this:
function bind(f, o) {
if (f.bind) return f.bind(o); // Use the bind method, if there is one
else return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
He illustrates the use of it with an example (which I have modified to change the 3rd line from f.bind(o)):
function f(y) { return this.x + y; } // This function needs to be bound
var o = { x : 1 }; // An object we'll bind to
var g = bind(f, o); // Calling g(x) invokes o.f(x)
g(2) // => 3
When I first saw this, I thought "Wouldn't arguments refer to the arguments variable within the bind function we're defining? But we want the arguments property of the function we eventually apply it to, like g in the example above..."
I verified that his example did indeed work and surmised that the line return f.apply(o, arguments) isn't evaluated until var g = bind(f, o) up above. That is, I thought, when you return a function, are you just returning the source code for that function, no? Until its evaluated? So I tested this theory by trying out a slightly different version of bind:
function mybind2(f, o) {
var arguments = 6;
return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
If it's simply returning tbe unevaluated function source, there's no way that it stores arguments = 6 when later evaluated, right? And after checking, I still got g(2) => 3. But then I realized -- if it's just returning unevaluated code, how is the o in return f.apply(o, arguments) getting passed?
So I decided that what must be happening is this:
The o and the arguments variables (even when arguments equals 6) are getting passed on to the function. It's just that when the function g is eventually called, the arguments variable is redefined by the interpreter to be the arguments of g (in g(2)) and hence the original value of arguments that I tried to pass on was replaced. But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
(Question 2) Earlier on the same page, he defines the following function which makes use the apply method to trace a function for debugging:
function trace(o, m) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
Question 1
For your first question, let's simplify the example so it's clear what being done:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
What happens here is that a closure is created that allows the access of the original function and the value of this that is passed. The anonymous function returned will keep the original function in its scope, which ends up being like the following:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
About your issue with arguments, that variable is implicitly defined in the scope of all functions created, so therefore the inner arguments will shadow the outer arguments, making it work as expected.
Question 2
Your problem is to your misunderstanding of the late binding of this -- this is one of the more confusing things about JavaScript to people used to more object-oriented languages that also have their own this keyword. The value of this is only set when it is called, and where it is called defines the value of this when it is called. It is simply the value of the parent object from where it is at the time the function is called, with the exception of cases where the this value is overridden.
For example, see this:
function a() {return this;};
a(); // global object;
var b = {};
b.a = a;
b.a(); // object b
If this was set when the function was defined, calling b.a would result in the global object, not the b object. Let's also simplify what happens with the second function given:
function trace(obj, property) {
var method = obj[property]; // Remember original method in the closure.
obj[property] = function () { // Now define the new method.
console.log(1); // Log message.
// Invoke original method and return its result
return original.apply(this, arguments);
};
}
What happens in this case is that the original method is stored in a closure. Assigning to the object that the method was originally in does not overwrite the method object. Just like a normal method assignment, the principles of the this value still work the same -- it will return the parent object, not the function that you've defined. If you do a simple assignment:
var obj = {};
obj.foo = function () { return this; };
obj.foo(); // obj
It does what was expected, returns the parent object at the time of calling. Placing your code in a nested function makes no difference in this regard.
Some good resources
If you'd like to learn more about writing code in JavaScript, I'd highly recommend taking a look at Fully Understanding the this Keyword by Cody Lindley -- it goes into much more detail about how the this keyword behaves in different contexts and the things you can do with it.
But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
No. this and arguments are just special variables which are implicitly set when a function is executed. They don't adhere to normal "closure rules". The function definition itself is still evaluated immediately and bind returns a function object.
You can easily verify this with:
var g = bind(f, o);
console.log(typeof g);
Here is a simpler example which doesn't involve higher order functions:
var arguments = 42;
function foo() {
console.log(arguments);
}
foo(1, 2);
I think you see that the definition of foo is evaluated like you'd expect. Yet, console.log(arguments) logs [1, 2] and not 42.
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
this never refers to the function itself (unless you explicitly set it so). The value of this is completely determined by how the function is called. That's why this is often called "the context". The MDN documentation provides extensive information about this.
Reading material:
MDN - this
MDN - arguments

Setting a variable equal to a function without parenthesis? [duplicate]

This question already has answers here:
What is the difference between a function call and function reference?
(6 answers)
Closed last year.
I was following a tutorial on AJAX, and the person making the video did something strange. At least I hadn't seen it before. They set an object property equal to a function name, but without the familiar (). He later went on to define the function. Code is provided below for context. Anyway, what does it mean to set something equal to a function without the parameters? That line of code is indeed running the function that is named that as you can see below.
xmlHTTP.onreadystatechange = handleServerResponse;
There's a function called "handleServerResponse()", that this line actually runs. I can post it, but I think it's irrelevant. It's just a normal function function handleServerResponse(). Any explanation would be greatly appreciated!
Thanks!
~Carpetfizz
EDIT: Adding () to the end of that line, creates errors, as well as changing it.
What they're doing there is referring to the function without calling it.
var x = foo; // Assign the function foo to x
var y = foo(); // Call foo and assign its *return value* to y
In JavaScript, functions are objects. Proper objects. And so you can pass references to them around.
In that specific case, what they're doing is setting up handleServerResponse as the callback that the XHR object uses when the ready state changes. The XHR object will call that function during the course of doing the ajax request.
Some more examples:
// Declare a function
function foo() {
console.log("Hi there");
}
// Call it
foo(); // Shows "Hi there" in the console
// Assign that function to a varible
var x = foo;
// Call it again
x(); // Shows "Hi there" in the console
// Declare another function
function bar(arg) {
arg();
}
// Pass `foo` into `bar` as an argument
bar(foo); // Shows "Hi there" in the console, because `bar`
// calls `arg`, which is `foo`
It follows on naturally from the fact that functions are objects, but it's worth calling out specifically that there's no magic link between x and foo in the above; they're both just variables that point to the same function. Other than the fact they point to the same function, they're not linked in any way, and changing one (to point at another function, for instance) has no effect on the other. Example:
var f = function() {
console.log("a");
};
f(); // "a"
var x = f;
x(); // "a"
f = function() {
console.log("b");
};
f(); // "b"
x(); // "a" (changing `f` had no effect on `x`)
When the state of the request changes (for example when the browser received the complete answer), the browser will call a function stored in the onreadystatechange property of the xmlHttpRequest. This call will be something like
xmlHTTP.onreadystatechange();
which will be just equivalent to
handleServerResponse();
To decide what function will be called, you assign this function (not the returned value of this function) to this property using the line you show.
This is possible because JavaScript is a language where functions are said first class : they may be property values just like objects, strings, etc.
It means you are assigning the variable a reference to that function. The reference then can be used to call the function instead. Something like this...
function foo(){
alert("I am inside foo");
}
var bar = foo; // bar now points to foo
// Call foo
foo();// alerts "I am inside foo";
// Call bar which is pointing to foo
bar();// alerts "I am inside foo";

What does "Object.call" mean?

function bb_graphics_GraphicsContext(){
Object.call(this);
this.bbdevice=null;
this.bbmatrixSp=0;
this.bbix=1.000000;
this.bbiy=0;
this.bbjx=0;
this.bbjy=1.000000;
this.bbtx=0;
this.bbty=0;
this.bbtformed=0;
this.bbmatDirty=0;
this.bbcolor_r=0;
this.bbcolor_g=0;
this.bbcolor_b=0;
this.bbalpha=0;
this.bbblend=0;
this.bbscissor_x=0;
this.bbscissor_y=0;
this.bbscissor_width=0;
this.bbscissor_height=0;
this.bbmatrixStack=new_number_array(192);
}
What does Object.call(this) mean?
Functions in JavaScript are full-fledged objects. They also, when passed as an argument to another function, don't retain their scope. So, in the following code...
var obj1 = {
property1: "blah",
method1: function () {
alert(this.property1);
// do stuff
}
};
function func1 (passedFunction) {
passedFunction();
// do other stuff
}
func1(obj1.method1);
... func1 will call obj1.method1, but it won't alert the value of obj1's property1, because all we've done is pass the function object, not its this context. That's where call and apply come in. They allow you to inject scope, tell the function what the meaning of this will be. The following example works:
var obj1 = {
property1: "blah",
method1: function () {
alert(this.property1);
// do stuff
}
};
function func1 (passedObject, passedFunction) {
passedFunction.call(passedObject);
// do other stuff
}
func1(ob1, obj1.method1);
Now, we've forced or explicitly told obj1.method1 what its context will by invoking call, and passing it the object it's to use as this.
call and apply are almost identical, except for how they handle additional arguments to the function being invoked. See these articles on MDN for more information: call, apply and Function.
All of this having been said, bb_graphics_GraphicsContext is a constructor. (Which you've probably guessed.) You invoke it by using the new keyword, var obj1 = new bb_graphics_GraphicsContext();. When it reaches line 1 of the function, it takes the this object, and calls the generic Object constructor, explicitly injecting the new object this (in the bb_graphics_GraphicsContext constructor) as the this of the Object constructor. I'd assume the writer of this function/constructor was doing this to make sure that the newly created object in bb_graphics_GraphicsContext was getting all the base methods of the base Object. But I don't know why this would be necessary, as if you call bb_graphics_GraphicsContext with the new keyword it will grab all these properties naturally.
Object.call will execute a certain function under the provided context, it can be used to call functions from one object on an other.
The mozilla dev network provides a very good explanation
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
This will do absolutely nothing except wasting resource and memory allocation.
If the Object.call(this) will have been assigned to a variable or property of the function constructor bb_graphics_GraphicsContext
this.myObject = Object.call(this)
The only thing that you get in that instance is an empty object "THAT DO NO HOLD THE PROVIDED CONTEXT"
function MyConstructor(){
this.test01 = 0;
var b = Object.call(this); // similar to b = {}; or b = new Object()
console.log(b); // log object
console.log(b.test); // log undefined
this.test = 1;
}
var myObject = new MyConstructor();
console.log(myObject, window.test01)
Although Object.call will probably do nothing as expressed here, the concept might be important. Basically, the example you will see on inheritance in the Node.js documentation is:
const util = require('util');
const EventEmitter = require('events');
function MyStream() {
EventEmitter.call(this);
}
util.inherits(MyStream, EventEmitter);
The util.inherits will make a new MyStream inherit (have the same prototype as) EventEmmiter. This could be enough if we are interested in MyStream having access to the functions inherited through the EventEmmiter prototype. But what if there are variables passed on construction? What if we have:
function MyObject() {
this.code = "2nV_ahR";
}
In this case, the code variable is passed on runtime when MyObject gets instantiated. Therefore, a subclass needs to pass:
function MySubObject() {
MyObject.call(this);
}
In order to inherit the code variable. What call does accept a parameter that sets the this variable. So... when I do var o = new MySubObject(), the this inside of MySubObject refers to o, which is then passed to the call method, so that when MyObject does this.code = ... it is actually passing the code to o!
Every JavaScript function has a toString(), call() and apply().
Read more about them on this odetocode.com article

Set "this" variable easily?

I have a pretty good understanding of Javascript, except that I can't figure out a nice way to set the "this" variable. Consider:
var myFunction = function(){
alert(this.foo_variable);
}
var someObj = document.body; //using body as example object
someObj.foo_variable = "hi"; //set foo_variable so it alerts
var old_fn = someObj.fn; //store old value
someObj.fn = myFunction; //bind to someObj so "this" keyword works
someObj.fn();
someObj.fn = old_fn; //restore old value
Is there a way to do this without the last 4 lines? It's rather annoying... I've tried binding an anonymous function, which I thought was beautiful and clever, but to no avail:
var myFunction = function(){
alert(this.foo_variable);
}
var someObj = document.body; //using body as example object
someObj.foo_variable = "hi"; //set foo_variable so it alerts
someObj.(function(){ fn(); })(); //fail.
Obviously, passing the variable into myFunction is an option... but that's not the point of this question.
Thanks.
There are two methods defined for all functions in JavaScript, call(), and apply(). The function syntax looks like:
call( /* object */, /* arguments... */ );
apply(/* object */, /* arguments[] */);
What these functions do is call the function they were invoked on, assigning the value of the object parameter to this.
var myFunction = function(){
alert(this.foo_variable);
}
myFunction.call( document.body );
I think you're looking for call:
myFunction.call(obj, arg1, arg2, ...);
This calls myFunction with this set to obj.
There is also the slightly different method apply, which takes the function parameters as an array:
myFunction.apply(obj, [arg1, arg2, ...]);
If you want to 'store' the this value to a function so that you can call it seamlessly later (e.g. when you don't have access to that value anymore), you can bind it (not available in all browsers though):
var bound = func.bind(someThisValue);
// ... later on, where someThisValue is not available anymore
bound(); // will call with someThisValue as 'this'
My search on how to bind this brought me here so I am posting my findings: In 'ECMAScript 2015' we can also set this lexically using arrow functions to.
See: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Instead of:
function Person() {
setInterval(function growUp() {
// The callback refers to the `self` variable of which
// the value is the expected object.
this.age++;
}.bind(this), 1000);
}
We can now do:
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the person object
}, 1000);
}
var p = new Person();
Setting the this keyword in javascript.
Javascript has 3 built in methods for setting the this keyword conveniently. They are all located on the Function.prototype object so every function can use them (since every function inherits from this prototype via prototypal inheritance). These functions are the following:
Function.prototype.call(): This function takes the object which you want to use as this as a first argument. Then the remainder of the arguments are the respective arguments of the function which is called.
Function.prototype.apply(): This function takes the object which you want to use as this as a first argument. Then the second argument is an array which contains the values of the arguments of the function which is called (first element of array is first argument of the function, second argument of the array is second argument of function etc.).
Function.prototype.bind(): This function returns a new function which has a different value of this. It takes the object which you want to set as the this value as a first argument and then returns a new function object.
Difference between call/apply and bind:
call and apply are similar in the fact that they immediately call the function (with a predefined value of this)
bind is different from call and apply in the fact that this function returns a new function with a different binding of the this value.
Examples:
const thisObj = {
prop1: 1,
prop2: 2,
};
function myFunc(arg1, arg2) {
console.log(this.prop1, this.prop2);
console.log(arg1, arg2);
}
// first arg this obj, other arguments are the
// respective arguments of the function
myFunc.call(thisObj, 'Call_arg1', 'Call_arg2');
// first arg this obj, other argument is an array which
// are the respective arguments of the function
myFunc.apply(thisObj, ['Apply_arg1', 'Apply_arg2']);
// the bind method returns a new function with a different
// this context which is stored in the newMyFunc variable
const newMyFunc = myFunc.bind(thisObj);
// now we can call the function like a normal function
newMyFunc('first', 'second');

Categories

Resources