53

The problem in example 1 is 'this' referring to the global name instead of the myName object.

I understand the use of bind() in setting the value of this to a specific object, so it solves the problem in example 1, but why does this problem occur in the first place? Is it just the way Javascript was created?

I'm also wondering why example 3 solves the issue and the difference between example 2 and 3.

this.name = "John"

var myName = {
  name: "Tom",
  getName: function() {
    return this.name
  }
}

var storeMyName = myName.getName; // example 1
var storeMyName2 = myName.getName.bind(myName); // example 2
var storeMyName3 = myName.getName(); // example 3

console.log("example 1: " + storeMyName()); // doesn't work
console.log("example 2: " + storeMyName2()); // works
console.log("example 3: " + storeMyName3); // works
Tom
  • 1,636
  • 2
  • 13
  • 21
  • 3
    *"Is it just the way Javascript was created?"* I guess yes. The value of `this` is determined dynamically, unless it is a bound or an arrow function. Not sure what else you want to know expect [learning about how `this` works](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch1.md). – Felix Kling Dec 30 '16 at 05:51
  • Possible duplicate of [Javascript call() & apply() vs bind()?](http://stackoverflow.com/questions/15455009/javascript-call-apply-vs-bind) – Azad Dec 30 '16 at 05:52
  • 4
    *"I'm also wondering why example 3 solves the issue"* `storeMyName` and `storeMyName2` contain *functions* whereas `storeMyName3` contains the *result* of *calling* `myName.getName()`. Big difference. I made this comparison between ways of calling a function and `.bind`: https://twitter.com/fkling42/status/736228742008176640 . Maybe it helps somehow. – Felix Kling Dec 30 '16 at 05:53
  • https://medium.com/@dave_lunny/bind-for-dummies-5d1a750725b8#.liz1lnoo1 – Dave Lunny Jan 05 '17 at 17:25
  • This is a great read. It has cleared up everything about `this` in JS for me: https://rainsoft.io/gentle-explanation-of-this-in-javascript/ – Greg Jan 09 '17 at 11:54

4 Answers4

69

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:

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • thanks a lot for your help and the resources. I'm new to javascript and you made the answer very obvious for me. So call()/apply() is the same as example 3, except used when the getName() method is separate from the object? – Tom Dec 30 '16 at 06:33
  • Basically yes. If a function is a property of an object, then calling the function as `myName.getName()` will implicitly set `this` to `myName`. It's equivalent to `myName.getName.call(myName)`. – Felix Kling Dec 30 '16 at 06:35
6

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.

So, when you execute var storeMyName = myName.getName; the first time, it takes the global name ( this.name = "John" )

When you use bind() function, it starts referring to the name defined in the current closure ( myName in this case ) and hence prints Tom

Third time, since the function is called right away its scope is within its own local object and thus prints the value in the closure Tom

Dmitry Pavlov
  • 30,789
  • 8
  • 97
  • 121
mrid
  • 5,782
  • 5
  • 28
  • 71
4

An analogy i like, which i have never seen anywhere: Let say you have a foo object with a bar function. When you are binding the bar function to another variable (or passing it as a function parameter, which is more common case with callbacks), you are not binding/passing the function with his enclosing object but only the "nude" function. Hence with the "nude" function, this means the global object.

A small demo

var foo = "global foo"; //foo set on the global object
var a = {foo : "object foo", bar : function(){return this.foo;}};
var bound = a.bar;
console.log(bound());//returns "global foo", not "object foo"

bound just point to the function(){return this.foo;}

Vincent J
  • 761
  • 1
  • 5
  • 22
1

Bind is the mechanism by which you can change the context(here your default context is global) of execution.

Based on your example -

var storeMyName = myName.getName;

From above line is you are executing storeMyName function in global context, so for this execution this.name will be top line(i.e. global one / "John").

var storeMyName2 = myName.getName.bind(myName);

For above line you are Explicitly changing the context of execution for storeMyName2 function(by saying that i don't want to execute this function as global function i want to execute this function in context of myName object, so in this case this.name will be "Tom")

var storeMyName3 = myName.getName(); // example 3

And for this above line you are just executing function on myName object context, more importantly you are not executing the storeMyName3 and that's why its context is not global one.

Dhruv
  • 173
  • 11