Javascript call () & apply () vs bind ()?

Я уже знаю, что apply и call аналогичные функции, которые устанавливаютthis (контекст функции).

разница в том, как мы отправляем аргументы (ручной vs array)

вопрос:

но когда я должен использовать 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

16 ответов


использовать .bind() когда вы хотите, чтобы эта функция позже вызывалась с определенным контекстом, полезным в событиях. Использовать .call() или .apply() если вы хотите немедленно вызвать функцию, и изменить контекст.

вызов / применить вызов функции немедленно, тогда как bind возвращает функцию, которая при последующем выполнении будет иметь правильный контекст для вызова исходной функции. Таким образом, вы можете поддерживать контекст в асинхронных обратных вызовах и событиях.

Я делаю это лот:

function MyObject(element) {
    this.elm = element;

    element.addEventListener('click', this.onClick.bind(this), false);
};

MyObject.prototype.onClick = function(e) {
     var t=this;  //do something with [t]...
    //without bind the context of this function wouldn't be a MyObject
    //instance as you would normally expect.
};

Я широко использую его в узле.js для асинхронных обратных вызовов, для которых я хочу передать метод-член, но все же хочу, чтобы контекст был экземпляром, который запустил асинхронное действие.

простая, наивная реализация bind будет выглядеть так:

Function.prototype.bind = function(ctx) {
    var fn = this;
    return function() {
        fn.apply(ctx, arguments);
    };
};

есть больше (например, передача других args), но вы можете прочитать больше об этом и увидеть реальную реализацию на MDN.

надеюсь, что это помогает.


они все придаем этой в функцию (или объект), и разница заключается в вызове функции (см. ниже).

вызов придает этой в функцию и выполняет функцию немедленно:

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"

bind придает этой в функцию, и ее нужно вызывать отдельно следующим образом:

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"

применить похож на вызов за исключением того, что он принимает объект типа массива вместо перечисления аргументов по одному:

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"                                     

ответ в простейшей форме

  • вызов вызывает функцию и позволяет передавать аргументы по один.
  • применить вызывает функцию и позволяет передавать аргументы в виде массива.
  • Bind возвращает новую функцию, позволяющую передать этот массив и любое количество аргументов.

применить против вызова против привязки Примеры

вызов

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.call(person1, 'Hello'); // Hello Jon Kuperman
say.call(person2, 'Hello'); // Hello Kelly King

применить

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}

say.apply(person1, ['Hello']); // Hello Jon Kuperman
say.apply(person2, ['Hello']); // Hello Kelly King

Bind

var person1 = {firstName: 'Jon', lastName: 'Kuperman'};
var person2 = {firstName: 'Kelly', lastName: 'King'};

function say() {
    console.log('Hello ' + this.firstName + ' ' + this.lastName);
}

var sayHelloJon = say.bind(person1);
var sayHelloKelly = say.bind(person2);

sayHelloJon(); // Hello Jon Kuperman
sayHelloKelly(); // Hello Kelly King

Когда Использовать Каждый

и вполне заменимый. Просто решите, проще ли отправлять массив или список аргументов, разделенных запятыми.

Я всегда помню, какой из них, помня, что вызов для запятой (разделенный список) и применить для Матрица.

Bind немного отличается. Он возвращает новую функцию. И сразу же выполнить текущую функцию.

Bind отлично подходит для многих вещей. Мы можем использовать его для функций карри, как в приведенном выше примере. Мы можем взять простую функцию hello и превратить ее в helloJon или helloKelly. Мы также можем использовать его для таких событий, как onClick, где мы не знаем, когда они будут уволены, но мы знаем, какой контекст мы хотим, чтобы они имели.

Referance: codeplanet.io


Это позволяет установить значение 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);

предположим, что у нас есть 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

что делать, если я передам оба параметра в bind

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 создает функцию call и apply выполняет функцию тогда как apply ожидает параметры в array


и Function.prototype.call() и Function.prototype.apply() вызовите функцию с заданным this value и возвращает возвращаемое значение этой функции.

Function.prototype.bind(), С другой стороны, создает новую функцию с заданной this value и возвращает эту функцию без ее выполнения.

Итак, давайте возьмем функцию, которая выглядит так:

var logProp = function(prop) {
    console.log(this[prop]);
};

теперь давайте возьмем объект, который выглядит следующим образом:

var Obj = {
    x : 5,
    y : 10
};

мы можем привязать нашу функцию к нашему объекту такой :

Obj.log = logProp.bind(Obj);

теперь мы можем использовать Obj.log в любом месте в коде :

Obj.log('x'); // Output : 5
Obj.log('y'); // Output : 10

где это действительно становится интересным, это когда вы не только привязываете значение для this, но и для своего аргумента prop :

Obj.logX = logProp.bind(Obj, 'x');
Obj.logY = logProp.bind(Obj, 'y');

теперь мы можем сделать это :

Obj.logX(); // Output : 5
Obj.logY(); // Output : 10

вот один хорошая статья чтобы проиллюстрировать разницу между bind(), apply() и call(), обобщить его, как показано ниже.

  • bind() позволяет легко установить какой конкретно объект будет привязан к этой при вызове функции или метода.

    // 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() позвольте нам заимствовать методы

    // 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​
    

    одна проблема с этим примером заключается в том, что мы добавляем новый метод showData на


bind: Он связывает функцию с предоставленным значением и контекстом, но не выполняет функцию. Для выполнения функции необходимо вызвать функцию.

вызов: он выполняет функцию с контекста и параметров.

применить: он выполняет функцию с предоставленным контекстом и параметр как array.


вызов/применить немедленно выполняет функции:

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

bind не выполняет функцию сразу, но возвращает wrapped применить


  • Call вызывает функцию и позволяет передавать аргументы один за другим.
  • Apply вызывает функцию и позволяет передавать аргументы в виде массива.
  • Bind возвращает новую функцию, позволяющую передать в этот массив любое количество аргументов.

вызов применить и привязать. и насколько они разные.

позволяет узнать вызов и применить, используя любую ежедневную терминологию.

у вас три автомобиля your_scooter , your_car and your_jet которые начинаются с того же механизма (метода). Мы создали объект automobile методом push_button_engineStart.

var your_scooter, your_car, your_jet;
var automobile = {
        push_button_engineStart: function (runtime){
        console.log(this.name + "'s" + ' engine_started, buckle up for the ride for ' + runtime + " minutes");
    }
}

позволяет понять, когда и используется. Допустим, вы инженер и у вас есть your_scooter, your_car и your_jet, который не пришел с push_button_engine_start и вы хотите использовать третью сторону push_button_engineStart.

если вы запустите следующие строки кода, они выдадут ошибку. Почему?

//your_scooter.push_button_engineStart();
//your_car.push_button_engineStart();
//your_jet.push_button_engineStart();


automobile.push_button_engineStart.apply(your_scooter,[20]);
automobile.push_button_engineStart.call(your_jet,10);
automobile.push_button_engineStart.call(your_car,40);

таким образом, приведенный выше пример успешно дает your_scooter, your_car, your_jet функцию из автомобильного объекта.

давайте нырять глубже Здесь мы разделим эту строку кода. automobile.push_button_engineStart помогает нам получить используемый метод.

Далее мы используем apply или call используя точечную нотацию. automobile.push_button_engineStart.apply()

теперь применить и вызвать принять два параметра.

  1. контекст
  2. аргументы

Итак, здесь мы устанавливаем контекст в последней строке кода.

automobile.push_button_engineStart.apply(your_scooter,[20])

разница между вызовом и apply это просто то, что apply принимает параметры в виде массива, а call просто может принимать разделенный запятыми список аргументов.

что такое функция привязки JS?

функция bind в основном связывает контекст чего-то, а затем сохраняет его в переменную для выполнения на более поздней стадии.

давайте сделаем наш предыдущий пример еще лучше. Ранее мы использовали метод, принадлежащий автомобильному объекту и использовали его для оснащения your_car, your_jet and your_scooter. Теперь давайте представим, что мы хотим дать отдельный push_button_engineStart отдельно для того чтобы начать наши автомобили индивидуально на любом более последнем этапе исполнения желаем.

var scooty_engineStart = automobile.push_button_engineStart.bind(your_scooter);
var car_engineStart = automobile.push_button_engineStart.bind(your_car);
var jet_engineStart = automobile.push_button_engineStart.bind(your_jet);


setTimeout(scooty_engineStart,5000,30);
setTimeout(car_engineStart,10000,40);
setTimeout(jet_engineStart,15000,5);

все еще не удовлетворены?

давайте сделаем это ясно, как слеза. Время экспериментировать. Мы вернемся к вызову и применению приложения функции и попытаемся сохранить значение функции в качестве ссылки.

эксперимент ниже терпит неудачу, потому что вызов и применение вызываются немедленно, поэтому мы никогда не доходим до этапа хранения ссылки в переменной, где функция bind крадет шоу

var test_function = automobile.push_button_engineStart.apply(your_scooter);


function printBye(message1, message2){
console.log(message1 + " " + this.name + " "+ message2);
}

var par01 = { name:"John" };
var msgArray = ["Bye", "Never come again..."];

printBye.call(par01, "Bye", "Never come again...");//Bye John Never come again...
printBye.call(par01, msgArray);//Bye,Never come again... John undefined
//so call() doesn't work with array and better with comma seperated parameters 

//printBye.apply(par01, "Bye", "Never come again...");//Error
printBye.apply(par01, msgArray);//Bye John Never come again...

var func1 = printBye.bind(par01, "Bye", "Never come again...");
func1();//Bye John Never come again...

var func2 = printBye.bind(par01, msgArray);
func2();//Bye,Never come again... John undefined
//so bind() doesn't work with array and better with comma seperated parameters

представьте, bind недоступен. вы можете легко построить его следующим образом :

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

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

bindHelper(arguments);

    function sayHello() {
            //alert(this.message);
            return this.message;
    }
    var obj = {
            message: "Hello"
    };

    function x(country) {
            var z = sayHello.bind(obj);
            setTimeout(y = function(w) {
//'this' reference not lost
                    return z() + ' ' + country + ' ' + w;
            }, 1000);
            return y;
    }
    var t = x('India')('World');
    document.getElementById("demo").innerHTML = t;

Я думаю, что те же места из них: все они могут изменить это значение функции.Различия между ними: функция bind вернет новую функцию в результате; методы call и apply выполнят функцию немедленно, но apply может принять массив в качестве параметров,и он будет анализировать разделенный массив.И также, функция bind может быть Currying.


функция привязки должна использоваться, когда мы хотим назначить функцию с определенным контекстом, например.

var demo = {
           getValue : function(){ 
             console.log('demo object get value       function') 
            }
           setValue : function(){  
              setTimeout(this.getValue.bind(this),1000)           
           }
 }

в приведенном выше примере, если мы вызываем demo.функция setValue () и передайте это.функция getValue непосредственно, то она не вызывает демо.функция setValue напрямую, потому что это в setTimeout относится к объекту window, поэтому нам нужно передать контекст демо-объекта этому.функция getValue с помощью bind. это означает, что мы только передаем функцию с контекстом демо-объекта, не вызывая actully функция.

надеюсь, вы поняли .

для получения дополнительной информации, пожалуйста, ознакомьтесь функция привязки javascript знает подробно