web-dev-qa-db-ja.com

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

私はすでにapplycallがsetthis(関数のコンテキスト)に似た関数であることを知っています。

違いは、引数の送信方法(manual 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

713
Royi Namir

関数オブジェクト、関数呼び出し、call/applybindの間の比較を少し前に作成しました。

enter image description here

.bindを使用すると、this now を設定しながら、将来的に 関数を実行することができます は新しい関数オブジェクトを返すためです。

19
Felix Kling

その関数が後で特定のコンテキストで呼び出されるようにしたい場合は.bind()を使用してください。これはイベントに便利です。関数をすぐに呼び出してコンテキストを変更する場合は、.call()または.apply()を使用してください。

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.
};

私はメンバーメソッドを渡したい非同期コールバックのためにNode.jsで広く使用していますが、それでもコンテキストを非同期アクションを開始したインスタンスにしたいのです。

Bindの単純で素朴な実装は次のようになります。

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

それ以外にも(他の引数を渡すのと同じように)ありますが、それについてもっと読んで、実際の実装 MDN上 を見ることができます。

お役に立てれば。

738
Chad

それらはすべて this を関数(またはオブジェクト)に付加します。違いは関数呼び出しにあります(下記参照)。

call this を関数に付加し、その関数を直ちに実行します。

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 attach this を機能に追加するため、次のように個別に呼び出す必要があります。

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 と似ていますが、引数を1つずつ一覧表示するのではなく、配列のようなオブジェクトを使用する点が異なります。

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"                                     
413

SIMPLEST形式で回答する

  • Callは関数を呼び出し、引数を一つずつ渡すことを可能にします。
  • Applyは関数を呼び出し、配列として引数を渡すことを可能にします。
  • 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

バインド

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

それぞれを使用する場合

電話と申し込みはかなり互換性があります。配列とカンマ区切りの引数リストのどちらを送信するのが簡単かを決めてください。

Callはコンマ(区切りリスト)用で、ApplyはArray用です。

バインドは少し異なります。新しい関数を返します。 Call and Applyは直ちに現在の機能を実行します。

バインドは多くのことに最適です。上の例のように関数をカレーするためにそれを使うことができます。単純なhello関数を取り、それをhelloJonまたはhelloKellyに変えることができます。また、onClickのようなイベントが発生した場合には発生しませんが、コンテキストをどのようなコンテキストにしたいのかがわかっている場合にも使用できます。

参照: codeplanet.io

141
Amit Shah

関数がどのように呼び出されるかとは無関係に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);
52
jantimon

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は関数を作成し、callapplyは関数を実行しますが、applyは配列のパラメータを期待します

41
tk120404

Function.prototype.call()Function.prototype.apply() の両方の場合、指定されたthis値を使用して関数を呼び出し、その関数の戻り値を返します。

一方、 Function.prototype.bind() は、指定されたthisの値で新しい関数を作成し、実行せずにその関数を返します。

それでは、このような関数を見てみましょう。

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
28
John Slegers

bind :提供された値とコンテキストで関数をバインドしますが、関数を実行しません。機能を実行するには、機能を呼び出す必要があります。

call :与えられたコンテキストとパラメータで関数を実行します。

apply :与えられたコンテキストと パラメータを配列 として関数を実行します。

19
Siddhartha

bind()apply()call()の違いを説明するための 良い記事 を以下に要約します。

  • bind()を使用すると、関数またはメソッドが呼び出されたときにどの特定のオブジェクトをthisにバインドするかを簡単に設定できます。

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

    この例の問題の1つは、showDataオブジェクトに新しいメソッドcarsを追加することです。また、carsオブジェクトには既にプロパティまたはメソッド名showDataが含まれている可能性があるため、メソッドを借用するだけではそうしたくない場合があります。誤って上書きしたくありません。以下のApplyおよびCallの説明で見るように、ApplyまたはCallメソッドを使用してメソッドを借用するのが最善です。

  • bind()は、関数をカリー化することを許可します

    Function Currying は、partial function applicationとも呼ばれ、一部の引数が既に設定されている新しい関数を返す関数(1つ以上の引数を受け入れる)。

    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 + ".";
        }
     }
    

    bind()を使用して、このgreet関数をカリー化できます

    // 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()またはcall()this値を設定します

    applycall、およびbindメソッドはすべて、メソッドを呼び出すときにthis値を設定するために使用され、JavaScriptコードで直接制御と汎用性を使用できるようにわずかに異なる方法で設定します。

    applyメソッドとcallメソッドは、この値を設定する場合、関数パラメーターをapply ()an arrayとして渡し、パラメーターを個別にリストする必要があることを除いて、ほとんど同じですcall ()メソッドに渡します。

    以下に、callまたはapplyを使用して、コールバック関数でthisを設定する1つの例を示します。

    // 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
    
  • applyまたはcallで関数を借用する

    • 配列メソッドを借りる

      array-likeオブジェクトを作成し、いくつかの配列メソッドを借用して、配列のようなオブジェクトを操作します。

      // 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()を使用してvariable-arity関数を実行します

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 ()メソッドがvariadic functionsの実行に役立ちます。上記の代わりに、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
18
zangw

直ちに/ apply / functionを実行します。

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

bind は関数をすぐには実行しませんが、ラップされた apply functionを返します(後で実行するため)。

function bind(func, context) {
    return function() {
        return func.apply(context, arguments);
    };
}
8
  • Callは関数を呼び出し、引数を一つずつ渡すことを可能にします。
  • 適用は関数を呼び出し、配列として引数を渡すことを可能にします。
  • Bindは新しい関数を返すので、この配列と任意の数の引数を渡すことができます。
5
Khalid Azam

apply and bindを呼び出します。そしてそれらはどう違うのか。

電話を学び、毎日の用語を使用して適用することができます。

あなたは3つの自動車your_scooter , your_car and your_jetを持っていて、それらは同じメカニズム(方法)で始まります。メソッドPush_button_engineStartを使ってオブジェクトautomobileを作成しました。

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");
    }
}

電話や応募がいつ使用されるかを理解しましょう。あなたがエンジニアで、Push_button_engine_startに付属していないyour_scooteryour_car、およびyour_jetがあり、サードパーティの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を使うか、ドット表記を使って呼び出します。 automobile.Push_button_engineStart.apply()

今すぐ適用して呼び出す2つのパラメータを呼び出します。

  1. コンテキスト
  2. 引数

そこで、ここではコードの最終行にコンテキストを設定します。

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

callと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);

まだ満足していない?

それを涙としてはっきりさせましょう。実験する時間です。関数アプリケーションの呼び出しと適用に戻り、関数の値を参照として保存します。

Callとapplyはすぐに呼び出されるので、以下の実験は失敗します。したがって、バインド関数がショーを盗む場所である変数に参照を格納する段階には決して到達しません。

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

4
Sagar Munjal

呼び出し: 呼び出しは関数を呼び出し、引数を一つずつ渡すことを可能にします

適用: 適用は関数を呼び出し、配列として引数を渡すことを可能にします

Bind: Bindは新しい関数を返すので、この配列と任意の数の引数を渡すことができます。

var person1 = {firstName: 'Raju', lastName: 'king'};
var person2 = {firstName: 'chandu', lastName: 'shekar'};

function greet(greeting) {
    console.log(greeting + ' ' + this.firstName + ' ' + this.lastName);
}
function greet2(greeting) {
        console.log( 'Hello ' + this.firstName + ' ' + this.lastName);
    }


greet.call(person1, 'Hello'); // Hello Raju king
greet.call(person2, 'Hello'); // Hello chandu shekar



greet.apply(person1, ['Hello']); // Hello Raju king
greet.apply(person2, ['Hello']); // Hello chandu shekar

var greetRaju = greet2.bind(person1);
var greetChandu = greet2.bind(person2);

greetRaju(); // Hello Raju king
greetChandu(); // Hello chandu shekar
3
raju poloju

Call、Apply、Bindの基本的な違いは次のとおりです。

画像の後半で実行コンテキストを取得する場合は、バインドが使用されます。

例:

var car = { 
  registrationNumber: "007",
  brand: "Mercedes",

  displayDetails: function(ownerName){
    console.log(ownerName + ' this is your car ' + '' + this.registrationNumber + " " + this.brand);
  }
}
car.displayDetails('Nishant'); // **Nishant this is your car 007 Mercedes**

他の変数でこのメソッドを使用したいとしましょう

var car1 = car.displayDetails('Nishant');
car1(); // undefined

他の変数で車の参照を使用するには、使用する必要があります

var car1 = car.displayDetails.bind(car, 'Nishant');
car1(); // Nishant this is your car 007 Mercedes

バインド関数のより広範な使用について話しましょう

var func = function() {
 console.log(this)
}.bind(1);

func();
// Number: 1

どうして?現在funcはNumber 1でバインドされているため、その場合にバインドを使用しない場合、グローバルオブジェクトを指します。

var func = function() {
 console.log(this)
}.bind({});

func();
// Object

Call、Applyは、ステートメントを同時に実行する場合に使用されます。

var Name = { 
    work: "SSE",
    age: "25"
}

function displayDetails(ownerName) {
    console.log(ownerName + ", this is your name: " + 'age' + this.age + " " + 'work' + this.work);
}
displayDetails.call(Name, 'Nishant')
// Nishant, this is your name: age25 workSSE

In apply we pass the array
displayDetails.call(Name, ['Nishant'])
// Nishant, this is your name: age25 workSSE
3
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
2
Shiljo

想像してみてください、バインドは利用できません。次のように簡単に構成できます。

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;
0
pandhari