Why is JavaScript bind() necessary?
Why is JavaScript bind() necessary?
The value of this
is determined by how a function is called. If it is you who calls the function then there is usually no need to use .bind
, since you have control over how to call the function, and therefore its this
value.
However, often it is not you who calls the function. Functions are passed to other functions as callbacks and event handlers. They are called by other code and you have no control over how the function is called, and therefore cannot control what this
will refer to.
If your function requires this
to be set to a specific value and you are not the one calling the function, you need to .bind
the function to a specific this
value.
In other words: .bind
allows you to set the value of this
without calling the function now.
Here is comparison of referring to/calling functions:
+-------------------+-------------------+
| | |
| time of | time of |
|function execution | this binding |
| | |
+-------------------+-------------------+-------------------+
| | | |
| function object | future | future |
| f | | |
| | | |
+-------------------+-------------------+-------------------+
| | | |
| function call | now | now |
| f() | | |
| | | |
+-------------------+-------------------+-------------------+
| | | |
| f.call() | now | now |
| f.apply() | | |
| | | |
+-------------------+-------------------+-------------------+
| | | |
| f.bind() | future | now |
| | | |
+-------------------+-------------------+-------------------+
I'm also wondering why example 3 solves the issue and the difference between example 2 and 3.
Example 1/2 and 3 couldn't be more different. storeMyName
and storeMyName2
contain functions, which are called in the future, whereas storeMyName3
contains the result of calling myName.getName()
at that moment.
Further reading material:
- How does the "this" keyword work?
- MDN - this
- YDKS - this & Object Prototypes
- How to access the correct `this` context inside a callback?
Why is it necessary to use bind when working with ES6 and ReactJS?
bind
is just core javascript. It's how binding events works. It's not a React concept.
The following article explains it pretty well.
Bounded function in JavaScript is a function that is bounded to a given context. That means no matter how you call it, the context of the call will stay the same.
To create a bounded function out of the regular function, the bind method is used. bind method take context to which you want to bind your function as a first argument. The rest of arguments are arguments that will be always passed to such function. It returns a bounded function as a result.
http://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/
Also, on a side note, you should do all of your event binding in your constructor, not in your render method. This will prevent multiple bind calls.
Here's another good bit of information on the subject. They say:
We recommend that you bind your event handlers in the constructor so they are only bound once for every instance
https://facebook.github.io/react/docs/reusable-components.html
Why using bind is necessary in this implementation of curry function
There are only two reasons to ever use Function#bind
:
- When you want to bind the function to a particular context object. Practically speaking, when you want to make sure ahead of time that the
this
keyword inside the function will refer to a particular, known object. - When you want to pre-define some arguments, a.k.a. "partial function application".
The second case lends itself perfectly to what function currying is all about - making an N-ary function flexibly callable like:
fn(arg1, arg2, ..., argN)
, orfn(arg1, arg2, ...)(argN)
, orfn(arg1, arg2)(..., argN)
, orfn(arg1)(arg2)(...)(argN)
.
The important thing to notice here is that we need multiple separate functions for all cases but the first. Let's say you have a worker function that takes 3 arguments. You can...
- ...pass enough arguments for the worker function, i.e. 3 or more. Then
curry()
calls the worker function with those 3 arguments and returns the result.
This makesfn(arg1, arg2, arg3)
possible. - ...pass too few arguments for the worker function. Then
curry()
does not call the worker, but must return a new function which takes the remaining number of arguments.
This makes all offn(arg1)(arg2, arg3)
andfn(arg1, arg2)(arg3)
andfn(arg1)(arg2)(arg3)
possible.
Function#bind
covers the second case: It creates a new wrapper function for the worker and pre-fills some of the worker's argument slots with the given values. The context object is irrelevant for that intention, so using null
here is fine.
const curry = (fn, arity = fn.length, ...args) =>
// enough arguments ? call : remember arguments so far & defer
args.length >= arity ? fn(...args) : curry.bind(null, fn, arity, ...args);
So to answer the question: No, you can't use return curry(fn, arity, ...args)
because this does not do the most important thing, which is to create a new function.
Example: Let's say we have a worker function that searches a string and returns the number of hits.
const search = (str, substr) => {
var hits = 0, pos = 0;
while (true) {
pos = str.indexOf(substr, pos) + 1;
if (pos) hits++; else return hits;
}
}
Now we could create a curried version that remembers the target string for us and we only need to switch the last argument:
const flexibleSearch = curry(search);
const reusableSearch = flexibleSearch("... a ... b ... c ... a ... b ... a");
reusableSearch("a") // -> 3
reusableSearch("b") // -> 2
reusableSearch("c") // -> 1
reusableSearch("d") // -> 0
What is the use of the JavaScript 'bind' method?
Bind creates a new function that will force the this
inside the function to be the parameter passed to bind()
.
Here's an example that shows how to use bind
to pass a member method around that has the correct this
:
var myButton = {
content: 'OK',
click() {
console.log(this.content + ' clicked');
}
};
myButton.click();
var looseClick = myButton.click;
looseClick(); // not bound, 'this' is not myButton - it is the globalThis
var boundClick = myButton.click.bind(myButton);
boundClick(); // bound, 'this' is myButton
Which prints out:
OK clicked
undefined clicked
OK clicked
You can also add extra parameters after the 1st (this
) parameter and bind
will pass in those values to the original function. Any additional parameters you later pass to the bound function will be passed in after the bound parameters:
// Example showing binding some parameters
var sum = function(a, b) {
return a + b;
};
var add5 = sum.bind(null, 5);
console.log(add5(10));
Which prints out:
15
Check out JavaScript Function bind for more info and interactive examples.
Update: ECMAScript 2015 adds support for =>
functions. =>
functions are more compact and do not change the this
pointer from their defining scope, so you may not need to use bind()
as often. For example, if you wanted a function on Button
from the first example to hook up the click
callback to a DOM event, the following are all valid ways of doing that:
var myButton = {
... // As above
hookEvent(element) {
// Use bind() to ensure 'this' is the 'this' inside click()
element.addEventListener('click', this.click.bind(this));
}
};
Or:
var myButton = {
... // As above
hookEvent(element) {
// Use a new variable for 'this' since 'this' inside the function
// will not be the 'this' inside hookEvent()
var me = this;
element.addEventListener('click', function() { me.click() });
}
};
Or:
var myButton = {
... // As above
hookEvent(element) {
// => functions do not change 'this', so you can use it directly
element.addEventListener('click', () => this.click());
}
};
Please explain simply when/why I need to use bind()
Simple experiment to understand this:
Make 2 Js files. In first file, define a variable with some value and print it. In second file, change the value of that variable and print again.
File 1:
let x = 0; // variable declared here
console.log(x);
File 2:
x = 2; // no variable x declared just value change
console.log(x);
Now when you include both files in your HTML page (File 1 before File 2), the output is:
0
2
Conclusion: You can access variable in one file from another file on a single page. The variables are common for a page !
Now consider defining something in ReactJs class or method component. Since React is Js library only, you would be able to access functions inside the class without an object of the class ! This will defeat the purpose of abstraction and encapsulation. So, what bind
keyword does is, it tells that this function is bound to this class only and cannot be accessed outside it. That is why it is important to bind everything to your component. Otherwise two components using same function name might get confused which function to actually call if you don't bind them.
So, first time when you bind them, use the bind
keyword and then use it without bind
. Or, you can simply create arrow functions which will auto bind them to the component.
When to use .bind() in JS
In a nutshell, .bind()
returns a new function that when called will call the original function with a specific this
value and (optionally) some new arguments preprended to the argument list.
.bind()
is used when you need to pass a callback (e.g. some sort of function reference), but you want the caller to call your function with a specific this
value. This is most common when your function is actually a method and you want the this
value set to be the a specific object so the method will operate on that specific object . If you don't use .bind()
in those cases, then the this
value will be determined by the caller (not you) and if the caller doesn't set it specifically, it will end up being the global object or (in strict mode) undefined
. If what you were passing was a method that relies on a specific value of this
in order to do its job, it would not work properly with the wrong this
value.
So, if you want to control the value of this
when your callback is called, you can use .bind()
. Internally, .bind()
just creates a small stub function that just remembers the this
value you pass it and calls your function with .apply()
to set the this
value. .bind()
is not magic as it can be done manually too.
.bind()
also has the capability to add extra arguments to the function so, if you want to add arguments beyond what the normal caller of the callback uses, you can specify those with .bind()
too. It creates a stub function that will add these extra arguments and set the this
value.
Let's say you have your Person
object and you want to hook a button up to the .say()
method for a particular Person
object.
<button id="talk">Talk</button>
And, if you tried this javascript:
"use strict";
var bob = new Person("Bob", "Smith");
document.getElementById("talk").addEventListener("click", bob.say);
What you would find is that the say()
method is called, but it would be missing two things. It would be missing the right this
reference (which would be set to the button
object because that's how addEventListener calls its callbacks) and it would be missing the argument that say(message)
expects.
So, you could solve this yourself with your own stub function that calls bob.say()
with all the right arguments:
"use strict";
var bob = new Person("Bob", "Smith");
document.getElementById("talk").addEventListener("click", function(e) {
bob.say("Hello");
});
Or, you could use .bind()
:
"use strict";
var bob = new Person("Bob", "Smith");
document.getElementById("talk").addEventListener("click", bob.say.bind(bob, "Hello"));
There is no magic in .bind()
. It can be entirely simulated in javascript. In fact, here's a polyfill for it from MDN:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
This may look more complicated than it is because of all the error checking, but it's really just return a new function that combines two sets of arguments and then calls the original function with a specific this
value.
How do I know when to use .bind() on a function in JS?
Credit to T.J. Crowder and Zapparatus for their answers, which provided helpful info. Also helpful were these 4 answers/articles: 1 2 3 4
However, these were either not entirely complete and/or very long-winded. So I have decided to combine all of my findings into one answer, along with code examples.
There are several considerations to factor in when determining whether this
or local/class variables will be available in a function:
- The function's containing scope
- The immediate predecessor in the call chain
- Whether the function is called directly or indirectly
Note: there is also strict mode (which yields undefined
's rather than window
objects) and arrow functions (which do not change this
from the containing scope).
Here are the explicit rules:
- By default,
this
is the global object, which in browser world iswindow
. - Inside a function in the global scope,
this
will still bewindow
, it does not change. - Inside a member function within a
class
or function-class (new function() { }
), inside a function-class's prototype (funcClass.prototype.func = function() { }
), inside a function called by a neighboring member function withthis
, or inside a function mapped in an object ({ key: function() { } }
) or stored in an array ([ function() { } ]
), if the function is called directly with the class/object/array as the immediate predecessor in the call chain (class.func()
,this.func()
,obj.func()
, orarr[0]()
),this
refers to the class/object/array instance. - Inside any closure's inner function (any function within a function), inside a returned function, inside a function called with a plain variable reference as its immediate predecessor in the call chain (regardless of where it actually lives!), or inside a function called indirectly (i.e. passed to a function (e.g.
.forEach(function() { })
) or set to handle an event),this
reverts back towindow
or to whatever the caller may have bound it to (e.g. events may bind it to the triggering object instance).- There is... however... one exception...: if inside a
class
's member function (and only aclass
, not a function-class), if a function within that loses itsthis
context (e.g. by being a closure's inner function), it becomesundefined
, rather thanwindow
...
- There is... however... one exception...: if inside a
Here is a JSFiddle with a bunch of code examples:
outputBox = document.getElementById("outputBox");
function print(printMe = "") { outputBox.innerHTML += printMe;}
function printLine(printMe = "") { outputBox.innerHTML += printMe + "<br/>";}
var someVar = "someVar";
function func(who) { printLine("Outer func (" + who + "): " + this); var self = this; (function() { printLine("Inner func (" + who + "): " + this); printLine("Inner func (" + who + ") self: " + self); })();}func("global");printLine();func.call(someVar, "someVar");
printLine();
function funcTwo(who) { printLine("Outer funcTwo (" + who + "): " + this); var self = this; return function funcThree() { printLine("Inner funcThree (" + who + "): " + this); printLine("Inner funcThree (" + who + ") self: " + self); };}funcTwo("global")();printLine();f = funcTwo("global f");f();printLine();funcTwo.call(someVar, "someVar")();
printLine();
object = { func: function(who) { printLine("Object outer (" + who + "): " + this); var self = this; (function() { printLine("Object inner (" + who + "): " + this); printLine("Object inner (" + who + ") self: " + self); })(); }}object.func("good");printLine();bad = object.func;bad("bad");
printLine();
function funcClass(who) { printLine("funcClass (" + who + "): " + this);}funcClass.prototype.func = function() { printLine("funcClass.prototype.func: " + this); self = this; (function() { printLine("funcClass.func inner: " + this); printLine("funcClass.func inner self: " + self); })();}fc = funcClass("bad");printLine();fc = new funcClass("good");fc.func("good");
printLine();
class classClass { constructor() { printLine("classClass constructor: " + this); } func() { printLine("classClass.func: " + this); self = this; (function() { printLine("classClass.func inner: " + this); printLine("classClass.func inner self: " + self); })(); } funcTwo() { this.func(); }}cc = new classClass();cc.func();printLine();printLine("Calling funcTwo:");cc.funcTwo();
printLine();
[0].forEach(function(e) { printLine("[0].forEach: " + this); printLine("[0].forEach someVar: " + someVar);});[0].forEach(function(e) { printLine("[0].forEach with [0]: " + this);}, [0]);
printLine();
arr = [ function(who) { printLine("Array (" + who + "): " + this); }, 1, 10, 100];arr[0]("good");arrFunc = arr[0];arrFunc("bad");
printLine();
var button = document.getElementById("button");button.onclick = function() { printLine("button: " + this);}button.click();button.onclick = func;button.click();
setTimeout(function() { printLine(); printLine("setTimeout: " + this); printLine("setTimeout someVar: " + someVar);}, 0);
setTimeout(fc.func, 0);setTimeout(cc.func, 0);
<input id="button" type="button" value="button"/><br/><br/><div id="outputBox" />
Related Topics
How to Update State.Item[1] in State Using Setstate
JavaScript Checking for Null VS. Undefined and Difference Between == and ===
What Is the Correct Way to Check for String Equality in JavaScript
Remove Property for All Objects in Array
Foreach on Queryselectorall Not Working in Recent Microsoft Browsers
How to Open a New Window and Insert HTML into It Using Jquery
Error: Failed to Execute 'Appendchild' on 'Node': Parameter 1 Is Not of Type 'Node'
Why Element.Style Always Return Empty in Js
Is It Safe to Store a Jwt in Localstorage with Reactjs
Switch Statement for Multiple Cases in JavaScript
What Are the Differences Between Deferred, Promise and Future in JavaScript
Es6 Variable Import Name in Node.Js
Why Is Value Undefined at .Then() Chained to Promise