Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
127 views
in Technique[技术] by (71.8m points)

javascript - When to use .bind() in JS

There is a ton of blogs and posts about how to use bind() and how it's different than call() and apply(), but there is very little examples to when or why should I use bind()

I found many of the examples given are very uncommon occurrences such as this:

"use strict";

function Person(firstName, lastName){
  this.firstName = firstName
  this.lastName = lastName
}

Person.prototype.say = function(message){
  return '[' + this + ']: ' + this.firstName + ' ' + this.lastName + ' said: "' + message + '"'
}

Person.prototype.toString = function(){
  return '[Person]'
}

moe = new Person("Mo", "El")


func = moe.say.bind(moe)

console.log(func("asdasda"))

I don't know when there is a time I want to make a function equal to some other variable and use that variable instead of the original function, let alone that variable is equal the binding of an instance of the Person object.

Any good examples?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...