Set "this" variable easily? - javascript

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');

Related

chaining call and bind with slice() to convert array-like objects to arrays [duplicate]

I am having some trouble wrapping my head around this function:
var toStr = Function.prototype.call.bind( Object.prototype.toString );
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​​​
How does this function accept an argument as seen in line 2?
Well,
Function.prototype.call references the "call" function, which is used to invoke functions with chosen this values;
The subsequent .bind refers to the "bind" function on the Function prototype (remember: "call" is a function too), which returns a new function that will always have this set to the passed-in argument.
The argument passed to "bind" is the "toString" function on the Object prototype, so the result of that whole expression is a new function that will run the "call" function with this set to the "toString" function.
The result, therefore, is like this code: Object.prototype.toString.call( param ). Then, the "console.log" call passes that function an array, and there you have it.
edit Note that Object.prototype.toString.call( param ) is like param.toString() really, when "param" is an object. When it's not, then the semantics of the "call" function are to turn it into one in the normal ways JavaScript does that (numbers -> Number, strings -> String, etc).
edit, 24 May2016 — That last sentence above is not accurate with ES2015. New JavaScript runtimes do not "autobox" primitive types when those are involved with a function call as a this value.
I assume you already know what .call and .bind do
toStr is now a function that essentially does:
function toStr( obj ) {
return Function.prototype.call.call( Object.prototype.toString, obj );
}
I.E it .calls the .call function with context argument set to the .toString function. Normally that part is already taken care of because you normally use .call as a property of some function which sets the function as the context for the .call.
The two lines of code are a function definition and then execution call of that definition with an empty array passed inside. The complexity lies in interpreting what 'this' will point to and why.
To help deduce the value of this I copied content from two links below to MDN's definitions of call and bind.
The bind() function creates a new function (a bound function) with the same function body as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(). Your code looks similar to a 'shortcut function' described on the bind page.
var unboundSlice = Array.prototype.slice; // same as "slice" in the previous example
var slice = Function.prototype.call.bind(unboundSlice);
// ...
slice(arguments);
With call, you can assign a different this object when calling an
existing function. this refers to the current object, the calling
object.With call, you can write a method once and then inherit it in
another object, without having to rewrite the method for the new
object.
When toStr is called it passes in an array to bind, of which the this pointer is bound.
With bind(), this can be simplified.
toStr() is a bound function to the call() function of Function.prototype, with the this value set to the toStr() function of Array.prototype. This means that additional call() calls can be eliminated.
In essence, it looks like a shortcut function override to the toString method.
JS to English translation -
var toStr = Function.prototype.call.bind( Object.prototype.toString );
The bind creates a new call function of Object.prototype.toString.
Now you can call this new function with any context which will just be applied to Object.prototype.toString.
Like this:
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​
Why not just calling Object.prototype.toString.call([]) ??
Answer:
Of course, you could. But the OPs method creates a dedicated and de-methodized function just for this purpose.
This really is called demethodizing.
bind() - Creates a new function that, when called, itself calls this function in the context of the provided this value, with a given sequence of arguments preceding any provided when the new function was called.
Read this documentation for more information about bind() in JavaScript
Angular example:
Parent component where we have a defined function and bind it to an object:
public callback: object;
constructor() {
this.callback= this.myFunction.bind(this);
}
public myFunction($event: any) {
// Do something with $event ...
}
(Parent html) passing the binded object to child component:
<child-component (callbackFunction)="callback($event)"></child-component>
Child component that receives the object that is bind to the parent function:
#Output() callbackFunction: EventEmitter<object> = new EventEmitter<object>();
public childFunction() {
...
this.callbackFunction.emit({ message: 'Hello!' });
...
}
You could do :
var toStr = Object.prototype.toString.call([]);
Problem with this is : call executes instantly.
What you want is to delay the execution of call.
*As function is an object too in Javascript, you can use any function as the first argument in 'call' instead of passing an object as 1st argument.*Also, you can use the dot on call like on any object.
Function.prototype.call.bind( Object.prototype.toString ) , makes a copy of the call function with it's 'this' sets to Object.prototype.toString .
You hold this new copy of call function in 'toStr'.
var toStr = Function.prototype.call.bind( Object.prototype.toString );
Now you can executes this new copy of call any time you need without the need of setting 'this' as it's 'this' is already bind to Object.prototype.toString .
This should make sense to you
Object.prototype.toString.call([]) //work well
You think this form is too long and cumbersome and you want to simplify it? This makes it easier to use later:
const toStr = Object.prototype.toString.call
toStr([]) // unfortunately, this does not work
You need to use bind to correct where this points to.
const toStr = Object.prototype.toString.call.bind(Object.prototype.toString)
toStr([]) //work well
Object.prototype.toString.call is just the same as Function.prototype.call
const toStr = Function.prototype.call.bind(Object.prototype.toString)
toStr([]) //done
summary
function f(){console.log(this, arguments)}
f.call is just the same as Function.prototype.call.bind(f)
f.call(1,2,3) is just the same as Function.prototype.call.bind(f,1)(2,3)

How does this Array.prototype and bind combination replace this arrow function

I'm reading trough this: https://hackernoon.com/functional-javascript-resolving-promises-sequentially-7aac18c4431e
and in one section the author talks about replacing the second arrow function with
Promise.resolve([])
.then(all => funcs[0].then(result => all.concat(result)))
this
Promise.resolve([])
.then(all => funcs[0].then(Array.prototype.concat.bind(all)))
I'm having trouble understanding how this works... Is the returned result being added as an argument implicitly into the concat function?
whatEverMethod.bind(thisValue) binds this to thisValue.
To understand, we can assume (though not actually) every method call
obj.method(arg0)
to equal to
obj.method.apply(obj, arg0)
where the first argument of .apply explicitly tells: which object I am working on (because likely in the definition of .method you may reference to some this value, such as this.prop0 = 10)
What bind does is very simple: bind a this value to a method call, so that when called, no longer uses the default this value based on environment.
For example:
let obj0 = {a: 1}
let obj1 = {a: 2}
obj0.change = function(value) {
this.a = value;
} // when declared, default environment is obj0, since it is a method of obj0
// Now, explicitly bind `this` inside of obj0.change to obj1
let changeFunc = obj0.change.bind(obj1);
// This creates a function that has `this` set to obj1, which has the format changeFunc(value)
changeFunc(10);
console.log(obj1.a) // should be 10, since it is now operating on obj1 (due to binding)
Therefore,
(Array.prototype.concat.bind(all))(someArr)
// is basically
all.concat(someArr)
// due to having the exactly the same `this` value
The reason why we may want to do this is probably all may not be an array. For example, it might be an array-like object, such as the arguments for functions, which looks like an array, but missing common array methods.
bind operates on a function, taking a value for this and returning a new function that calls the original function with the specified this value and the same arguments¹. In other words,
Array.prototype.concat.bind(all)
means
(...args) => Array.prototype.concat.call(all, ...args)
which is
(...args) => all.concat(...args)
and since one argument is being passed, that’s
result => all.concat(result)
There is no reason not to just write the arrow function here, by the way. It’s clearer and has no downsides.
¹ it can also add arguments.
As you must know, the function then receives a function/callback.
The function bind returns a function attaching a specific object as context this.
Array.prototype.concat.bind(all))
^
|
+---- This object 'all' will be the context
'this' for the function 'concat'.
So, the function then will call the callback (passing the all object implicitly) which is the new function returned by the function bind, in this case, the function concat from Array prototype.
Resource
Function.prototype.bind()
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

How does Function.prototype.call.bind work?

I am having some trouble wrapping my head around this function:
var toStr = Function.prototype.call.bind( Object.prototype.toString );
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​​​
How does this function accept an argument as seen in line 2?
Well,
Function.prototype.call references the "call" function, which is used to invoke functions with chosen this values;
The subsequent .bind refers to the "bind" function on the Function prototype (remember: "call" is a function too), which returns a new function that will always have this set to the passed-in argument.
The argument passed to "bind" is the "toString" function on the Object prototype, so the result of that whole expression is a new function that will run the "call" function with this set to the "toString" function.
The result, therefore, is like this code: Object.prototype.toString.call( param ). Then, the "console.log" call passes that function an array, and there you have it.
edit Note that Object.prototype.toString.call( param ) is like param.toString() really, when "param" is an object. When it's not, then the semantics of the "call" function are to turn it into one in the normal ways JavaScript does that (numbers -> Number, strings -> String, etc).
edit, 24 May2016 — That last sentence above is not accurate with ES2015. New JavaScript runtimes do not "autobox" primitive types when those are involved with a function call as a this value.
I assume you already know what .call and .bind do
toStr is now a function that essentially does:
function toStr( obj ) {
return Function.prototype.call.call( Object.prototype.toString, obj );
}
I.E it .calls the .call function with context argument set to the .toString function. Normally that part is already taken care of because you normally use .call as a property of some function which sets the function as the context for the .call.
The two lines of code are a function definition and then execution call of that definition with an empty array passed inside. The complexity lies in interpreting what 'this' will point to and why.
To help deduce the value of this I copied content from two links below to MDN's definitions of call and bind.
The bind() function creates a new function (a bound function) with the same function body as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(). Your code looks similar to a 'shortcut function' described on the bind page.
var unboundSlice = Array.prototype.slice; // same as "slice" in the previous example
var slice = Function.prototype.call.bind(unboundSlice);
// ...
slice(arguments);
With call, you can assign a different this object when calling an
existing function. this refers to the current object, the calling
object.With call, you can write a method once and then inherit it in
another object, without having to rewrite the method for the new
object.
When toStr is called it passes in an array to bind, of which the this pointer is bound.
With bind(), this can be simplified.
toStr() is a bound function to the call() function of Function.prototype, with the this value set to the toStr() function of Array.prototype. This means that additional call() calls can be eliminated.
In essence, it looks like a shortcut function override to the toString method.
JS to English translation -
var toStr = Function.prototype.call.bind( Object.prototype.toString );
The bind creates a new call function of Object.prototype.toString.
Now you can call this new function with any context which will just be applied to Object.prototype.toString.
Like this:
toStr([]) // [object Array]​​​​​​​​​​​​​​​​​​​​​​​​​
Why not just calling Object.prototype.toString.call([]) ??
Answer:
Of course, you could. But the OPs method creates a dedicated and de-methodized function just for this purpose.
This really is called demethodizing.
bind() - Creates a new function that, when called, itself calls this function in the context of the provided this value, with a given sequence of arguments preceding any provided when the new function was called.
Read this documentation for more information about bind() in JavaScript
Angular example:
Parent component where we have a defined function and bind it to an object:
public callback: object;
constructor() {
this.callback= this.myFunction.bind(this);
}
public myFunction($event: any) {
// Do something with $event ...
}
(Parent html) passing the binded object to child component:
<child-component (callbackFunction)="callback($event)"></child-component>
Child component that receives the object that is bind to the parent function:
#Output() callbackFunction: EventEmitter<object> = new EventEmitter<object>();
public childFunction() {
...
this.callbackFunction.emit({ message: 'Hello!' });
...
}
You could do :
var toStr = Object.prototype.toString.call([]);
Problem with this is : call executes instantly.
What you want is to delay the execution of call.
*As function is an object too in Javascript, you can use any function as the first argument in 'call' instead of passing an object as 1st argument.*Also, you can use the dot on call like on any object.
Function.prototype.call.bind( Object.prototype.toString ) , makes a copy of the call function with it's 'this' sets to Object.prototype.toString .
You hold this new copy of call function in 'toStr'.
var toStr = Function.prototype.call.bind( Object.prototype.toString );
Now you can executes this new copy of call any time you need without the need of setting 'this' as it's 'this' is already bind to Object.prototype.toString .
This should make sense to you
Object.prototype.toString.call([]) //work well
You think this form is too long and cumbersome and you want to simplify it? This makes it easier to use later:
const toStr = Object.prototype.toString.call
toStr([]) // unfortunately, this does not work
You need to use bind to correct where this points to.
const toStr = Object.prototype.toString.call.bind(Object.prototype.toString)
toStr([]) //work well
Object.prototype.toString.call is just the same as Function.prototype.call
const toStr = Function.prototype.call.bind(Object.prototype.toString)
toStr([]) //done
summary
function f(){console.log(this, arguments)}
f.call is just the same as Function.prototype.call.bind(f)
f.call(1,2,3) is just the same as Function.prototype.call.bind(f,1)(2,3)

What the difference between those two?

Is there any difference between these two:
var test1 = function () {
this.method1 = function() {}
}
and
var test2 = function() {};
test2.method1 = function() {};
The first snippet takes this object, whatever it is, and assigns a function to its slot (field) named method1. this can represent different objects, depending upon how test1 is called:
when called as a standalone function -- test1() -- this will be window
when called as a constructor -- new test1() -- this refers to the object being created
when called via call or apply -- test1.apply(someObject) -- this refers to the argument
The second snippet takes the object test2 and assigns a function to its slot named method1.
The first way is a constructor that creates more objects and needs to have the new keyword:
var mytest1 = new test1();
mytest1.method1();
The second way is ready to use right away:
test2.method1();
Assuming syntax was correct, the first is a constructor that gives all test1 objects created via new test1() a method called method1. The second just adds a function to the constructor object. In javascript, functions are objects which can have properties (including methods).
The first version actually creates a method available to all objects instantiated like so:
var o = new test1();
o.test1();
The second simply attached a function as an attribute on the test2 function. If you're familiar with other class-based OO languages, this works kinda like a static method. You will not have access to the this pointer in the second example.
The first one:
var test1 = function () {
this.method1 = function() {}
}
Defines the function "test1". Once (and only when) "test1" is called, "this.method1" will be defined as a function, that does nothing.
The second:
var test2 = function() {};
test2.method1 = function() {};
Create the function "test2" and at the same time defines the function "test2.method1", without the need to invoke the first function.
The first one sets the method1 property on whatever invokes test1().
The second one defines an empty function and sets the method1 property on test2

JS function returning another function

I want to understand about variables, that has been used in returning function.
This is example code
Prototype = {}
Prototype.F =
{
bind: function()
{
var args = arguments, __method = args.shift(), object = args.shift();
return function()
{
return __method.apply(object, args.concat(arguments));
}
}
}
function ObjectA()
{
...
this.addListener = Prototype.F.bind(this.eventSource.addListener,
this.eventSource);
...
}
var a = ObjectA();
a.addListener(this); // assuming 'this' here will point to some window object
As I understand the returning function in bind() is not evaluated until it's called in the last line. It's ok to accept. So addListener will hold a function body containing 'apply'.
But what I don't understand, when addListener is called, what kind of parameters it is going to have? particularly _method and args will always be uninitialized?
The function that bind returns is a closure over the arguments to the bind function, and so the __method argument will be the first argument to bind (in your example call, that will be the this.eventSource.addListener function).
Closures are basically functions that have data bound into them intrinsically. Here's a simpler example:
function makeAlert(msg) {
return function() {
alert(msg);
}
}
var myalert = makeAlert("Hi there!");
myalert(); // Alerts "Hi there!"
The function returned by makeAlert "closes over" (retains access to) the things in scope within the makeAlert function call that created it, including the msg argument. That's why when we call the function later, it still has msg even though the call to makeAlert has long since completed. More about closures here.
A key thing to remember about closures is that they retain access to everything that's in scope where they're defined, not just the things they they're obviously using. So for instance:
function init() {
var data;
data = /* ...build some really big array of data...*/;
document.getElementById('foo').onclick = function() {
this.style.display = "none";
};
}
Even though the event handler has nothing to do with the big data array, it keeps a reference to it, and so keeps that data in memory after the call to init has completed. This is because the link that it has is to a behind-the-scenes object (loosely called the "variable object") that is a container for all of the arguments and local variables in scope where it's defined. (In this particular case, if you don't need all that data, just set data to undefined at the end. The event handler will still have a reference to data, but that reference isn't holding the array anymore, so the array's memory can be reclaimed.)
_method and args will be always initialized, because you are defining them when you first call
this.addListener = Prototype.F.bind(this.eventSource.addListener, this.eventSource);
There, you'll get that _method will be that this.eventSource.addListener, and args will be those both arguments.
in the scope of a function, arguments is an array-like object which contains the values provided when the function is called, whether or not the function definition has parameters defined.
so for this call:
Prototype.F.bind(this.eventSource.addListener, this.eventSource);
which leads to this:
var args = arguments, __method = args.shift(), object = args.shift();
arguments contains 2 items: whatever this.eventSource.addListener and this.eventSource point to when the function is called. that collection of 2 items is copied to args, and then the items are moved from the colleciton to __method and object.
since the call bind actually generates another function, the arguments instance in the new function will be different- it'll have the parameters provided at the time of that call. the original arguments from the call to bind are saved in args and combined with arguments from the later function call.

Categories

Resources