Why Is JavaScript Bind() Necessary

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:

  1. 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.
  2. 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), or
  • fn(arg1, arg2, ...)(argN), or
  • fn(arg1, arg2)(..., argN), or
  • fn(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...

  1. ...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 makes fn(arg1, arg2, arg3) possible.
  2. ...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 of fn(arg1)(arg2, arg3) and fn(arg1, arg2)(arg3) and fn(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 is window.
  • Inside a function in the global scope, this will still be window, 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 with this, 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(), or arr[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 to window 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 a class, not a function-class), if a function within that loses its this context (e.g. by being a closure's inner function), it becomes undefined, rather than window...

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



Leave a reply



Submit