JavaScript call()和apply()与bind()?

我已经知道了,apply并且call是类似的函数集this(函数的上下文)。

区别在于我们发送参数的方式(手动vs数组)

题:

但是什么时候应该使用该 bind()方法?

var obj = {
  x: 81,
  getX: function() {
    return this.x;
  }
};

alert(obj.getX.bind(obj)());
alert(obj.getX.call(obj));
alert(obj.getX.apply(obj));

jsbin

斯丁小宇宙2020/03/11 10:32:49

I think the same places of them are: all of them can change the this value of a function.The differences of them are: the bind function will return a new function as a result; the call and apply methods will execute the function immediately, but apply can accept a array as params,and it will parse the array separated.And also, the bind function can be Currying.

村村小卤蛋2020/03/11 10:32:49

call():- 这里我们单独传递函数参数,而不是以数组格式传递

var obj = {name: "Raushan"};

var greeting = function(a,b,c) {
    return "Welcome "+ this.name + " to "+ a + " " + b + " in " + c;
};

console.log(greeting.call(obj, "USA", "INDIA", "ASIA"));

apply():- 这里我们以数组格式传递函数参数

var obj = {name: "Raushan"};

var cal = function(a,b,c) {
    return this.name +" you got " + a+b+c;
};

var arr =[1,2,3];  // array format for function arguments
console.log(cal.apply(obj, arr)); 

bind():-

       var obj = {name: "Raushan"};

       var cal = function(a,b,c) {
            return this.name +" you got " + a+b+c;
       };

       var calc = cal.bind(obj);
       console.log(calc(2,3,4));
Harry飞云2020/03/11 10:32:49

想象一下,绑定不可用。您可以轻松地将其构造如下:

var someFunction=...
var objToBind=....

var bindHelper =  function (someFunction, objToBind) {
    return function() {
        someFunction.apply( objToBind, arguments );
    };  
}

bindHelper(arguments);
蛋蛋L2020/03/11 10:32:49

bind:它将功能与提供的值和上下文绑定,但不执行该功能。要执行功能,您需要调用该功能。

call:使用提供的上下文和参数执行函数。

apply: It executes the function with provided context and parameter as array.

前端逆天2020/03/11 10:32:49

调用/应用立即执行功能:

func.call(context, arguments);
func.apply(context, [argument1,argument2,..]);

绑定不会立即执行功能,但会返回包装的应用功能(以供以后执行):

function bind(func, context) {
    return function() {
        return func.apply(context, arguments);
    };
}
樱十三2020/03/11 10:32:49

Here is one good article to illustrate the difference among bind(), apply() and call(), summarize it as below.

  • bind() allows us to easily set which specific object will be bound to this when a function or method is invoked.

    // This data variable is a global variable​
    var data = [
        {name:"Samantha", age:12},
        {name:"Alexis", age:14}
    ]
    var user = {
        // local data variable​
        data    :[
            {name:"T. Woods", age:37},
            {name:"P. Mickelson", age:43}
        ],
        showData:function (event) {
            var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1​
            console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
        }
    }
    
    // Assign the showData method of the user object to a variable​
    var showDataVar = user.showData;
    showDataVar (); // Samantha 12 (from the global data array, not from the local data array)​
    /*
    This happens because showDataVar () is executed as a global function and use of this inside 
    showDataVar () is bound to the global scope, which is the window object in browsers.
    */
    
    // Bind the showData method to the user object​
    var showDataVar = user.showData.bind (user);
    // Now the we get the value from the user object because the this keyword is bound to the user object​
    showDataVar (); // P. Mickelson 43​
    
  • bind() allow us to borrow methods

    // Here we have a cars object that does not have a method to print its data to the console​
    var cars = {
        data:[
           {name:"Honda Accord", age:14},
           {name:"Tesla Model S", age:2}
       ]
    }
    
    // We can borrow the showData () method from the user object we defined in the last example.​
    // Here we bind the user.showData method to the cars object we just created.​
    cars.showData = user.showData.bind (cars);
    cars.showData (); // Honda Accord 14​
    

    One problem with this example is that we are adding a new method showData on the cars object and we might not want to do that just to borrow a method because the cars object might already have a property or method name showData. We don’t want to overwrite it accidentally. As we will see in our discussion of Apply and Call below, it is best to borrow a method using either the Apply or Call method.

  • bind() allow us to curry a function

    Function Currying, also known as partial function application, is the use of a function (that accept one or more arguments) that returns a new function with some of the arguments already set.

    function greet (gender, age, name) {
        // if a male, use Mr., else use Ms.​
        var salutation = gender === "male" ? "Mr. " : "Ms. ";
        if (age > 25) {
            return "Hello, " + salutation + name + ".";
        }else {
            return "Hey, " + name + ".";
        }
     }
    

    We can use bind() to curry this greet function

    // So we are passing null because we are not using the "this" keyword in our greet function.
    var greetAnAdultMale = greet.bind (null, "male", 45);
    
    greetAnAdultMale ("John Hartlove"); // "Hello, Mr. John Hartlove."
    
    var greetAYoungster = greet.bind (null, "", 16);
    greetAYoungster ("Alex"); // "Hey, Alex."​
    greetAYoungster ("Emma Waterloo"); // "Hey, Emma Waterloo."
    
  • apply() or call() to set this value

    The apply, call, and bind methods are all used to set the this value when invoking a method, and they do it in slightly different ways to allow use direct control and versatility in our JavaScript code.

    The apply and call methods are almost identical when setting the this value except that you pass the function parameters to apply () as an array, while you have to list the parameters individually to pass them to the call () method.

    Here is one example to use call or apply to set this in the callback function.

    // Define an object with some properties and a method​
    // We will later pass the method as a callback function to another function​
    var clientData = {
        id: 094545,
        fullName: "Not Set",
        // setUserName is a method on the clientData object​
        setUserName: function (firstName, lastName)  {
            // this refers to the fullName property in this object​
            this.fullName = firstName + " " + lastName;
        }
    };
    
    function getUserInput (firstName, lastName, callback, callbackObj) {
         // The use of the Apply method below will set the "this" value to callbackObj​
         callback.apply (callbackObj, [firstName, lastName]);
    }
    
    // The clientData object will be used by the Apply method to set the "this" value​
    getUserInput ("Barack", "Obama", clientData.setUserName, clientData);
    // the fullName property on the clientData was correctly set​
    console.log (clientData.fullName); // Barack Obama
    
  • Borrow functions with apply or call

    • Borrow Array methods

      Let’s create an array-like object and borrow some array methods to operate on the our array-like object.

      // An array-like object: note the non-negative integers used as keys​
      var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };
      
       // Make a quick copy and save the results in a real array:
       // First parameter sets the "this" value​
       var newArray = Array.prototype.slice.call (anArrayLikeObj, 0);
       console.log (newArray); // ["Martin", 78, 67, Array[3]]​
      
       // Search for "Martin" in the array-like object​
       console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true​
      

      另一个常见情况是arguments如下转换为数组

        // We do not define the function with any parameters, yet we can get all the arguments passed to it​
       function doSomething () {
          var args = Array.prototype.slice.call (arguments);
          console.log (args);
       }
      
       doSomething ("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"]
      
    • 借用其他方法

      var gameController = {
           scores  :[20, 34, 55, 46, 77],
           avgScore:null,
           players :[
                {name:"Tommy", playerID:987, age:23},
                {name:"Pau", playerID:87, age:33}
           ]
       }
       var appController = {
           scores  :[900, 845, 809, 950],
           avgScore:null,
           avg     :function () {
                   var sumOfScores = this.scores.reduce (function (prev, cur, index, array) {
                        return prev + cur;
               });
               this.avgScore = sumOfScores / this.scores.length;
           }
         }
         // Note that we are using the apply () method, so the 2nd argument has to be an array​
         appController.avg.apply (gameController);
         console.log (gameController.avgScore); // 46.4​
         // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated​
         console.log (appController.avgScore); // null​
      
  • 使用apply()执行可变元数函数

Math.max是可变对数函数的一个示例,

// We can pass any number of arguments to the Math.max () method​
console.log (Math.max (23, 11, 34, 56)); // 56

但是,如果我们要传递一组数字Math.max怎么办?我们不能这样做:

var allNumbers = [23, 11, 34, 56];
// We cannot pass an array of numbers to the the Math.max method like this​
console.log (Math.max (allNumbers)); // NaN

这是该apply ()方法帮助我们执行可变函数的地方代替上面的方法,我们必须使用apply (传递数字数组

var allNumbers = [23, 11, 34, 56];
// Using the apply () method, we can pass the array of numbers:
console.log (Math.max.apply (null, allNumbers)); // 56
LEYTom2020/03/11 10:32:49

它允许设置值,this而与调用函数的方式无关。这在使用回调时非常有用:

  function sayHello(){
    alert(this.message);
  }

  var obj = {
     message : "hello"
  };
  setTimeout(sayHello.bind(obj), 1000);

要获得相同的结果,call将如下所示:

  function sayHello(){
    alert(this.message);
  }

  var obj = {
     message : "hello"
  };
  setTimeout(function(){sayHello.call(obj)}, 1000);
樱理查德2020/03/11 10:32:49

假设我们有multiplication功能

function multiplication(a,b){
console.log(a*b);
}

让我们使用创建一些标准函数 bind

var multiby2 = multiplication.bind(this,2);

现在multiby2(b)等于乘法(2,b);

multiby2(3); //6
multiby2(4); //8

如果我在绑定中传递了两个参数怎么办

var getSixAlways = multiplication.bind(this,3,2);

现在getSixAlways()等于乘法(3,2);

getSixAlways();//6

甚至传递参数返回6; getSixAlways(12); //6

var magicMultiplication = multiplication.bind(this);

这将创建一个新的乘法函数,并将其分配给magicMultiplication。

哦,不,我们将乘法功能隐藏在magicMultiplication中。

调用 magicMultiplication返回空白function b()

执行时效果很好 magicMultiplication(6,5); //30

打电话和申请怎么样?

magicMultiplication.call(this,3,2); //6

magicMultiplication.apply(this,[5,2]); //10

简而言之,bind创建函数callapply执行函数,而apply期望数组中的参数

小卤蛋Stafan2020/03/11 10:32:49

他们都重视为功能(或对象)不同的是在函数调用(见下文)。

呼叫重视为功能和立即执行的功能:

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
person.hello.call({ name: "Jim Smith" }, "world"); // output: "Jim Smith says hello world"

结合入功能和它需要被这样分开调用:

var person = {  
  name: "James Smith",
  hello: function(thing) {
    console.log(this.name + " says hello " + thing);
  }
}

person.hello("world");  // output: "James Smith says hello world"
var helloFunc = person.hello.bind({ name: "Jim Smith" });
helloFunc("world");  // output: Jim Smith says hello world"

或像这样:

...    
var helloFunc = person.hello.bind({ name: "Jim Smith" }, "world");
helloFunc();  // output: Jim Smith says hello world"

apply类似于call,不同之处在于apply接受一个类似数组的对象,而不是一次列出一个参数:

function personContainer() {
  var person = {  
     name: "James Smith",
     hello: function() {
       console.log(this.name + " says hello " + arguments[1]);
     }
  }
  person.hello.apply(person, arguments);
}
personContainer("world", "mars"); // output: "James Smith says hello mars", note: arguments[0] = "world" , arguments[1] = "mars"                                     
小哥Stafan2020/03/11 10:32:49

我在函数对象,函数调用call/applybind前一阵子之间创建了这种比较

在此处输入图片说明

.bind允许您设置的this现在同时允许执行的功能在未来,因为它返回一个新的函数对象。