Apa perbedaan antara panggilan dan terapkan?

Apa perbedaan antara menggunakan call dan apply untuk memanggil fungsi?

var func = function() {
  alert('hello!');
};

func.berlaku(); vs func.call();

Apakah ada perbedaan kinerja antara dua metode tersebut? Ketika itu yang terbaik untuk menggunakan panggilan atas apply dan sebaliknya?

Mengomentari pertanyaan (12)
Larutan

Perbedaannya adalah bahwa terapkan memungkinkan anda memanggil fungsi dengan argumen sebagai array; panggilan membutuhkan parameter dicantumkan secara eksplisit. Berguna mnemonic adalah "A untuk array dan C untuk comma."

Lihat MDN's dokumentasi pada apply dan panggilan.

Pseudo sintaks:

fungsi.menerapkan(valueForThis, arrayOfArgs)

fungsi.panggilan(valueForThis, arg1, arg2, ...)

Ada juga, seperti dari ES6, kemungkinan untuk menyebar array untuk digunakan dengan panggilan fungsi, anda dapat melihat kompatibilitas di sini.

Contoh kode:

function theFunction(name, profession) {
    console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator
Komentar (12)

K. Scott Allen telah bagus writeup tentang masalah ini.

Pada dasarnya, mereka berbeda tentang bagaimana mereka menangani argumen fungsi.

berlaku() metode ini identik dengan panggilan(), kecuali berlaku() membutuhkan sebuah array sebagai parameter kedua. Array merupakan argumen untuk metode target."

Jadi:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
Komentar (2)

Untuk menjawab bagian tentang kapan harus menggunakan setiap fungsi, penggunaan berlaku jika anda don't tahu jumlah dari argumen anda akan lewat, atau jika mereka sudah dalam array atau array-seperti objek (seperti argumen objek untuk meneruskan argumen anda sendiri. Gunakan panggilan jika tidak, sejak ada's tidak perlu untuk membungkus argumen dalam array.

f.call(thisObject, a, b, c); // Fixed number of arguments

f.apply(thisObject, arguments); // Forward this function's arguments

var args = [];
while (...) {
    args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments

Ketika saya'm tidak melewati argumen (seperti contoh), saya lebih memilih panggilan sejak saya'm menelepon fungsi. terapkan akan berarti anda menerapkan fungsi untuk (tidak ada) argumen.

Seharusnya't akan ada perbedaan kinerja, kecuali mungkin jika anda menggunakan apply dan bungkus argumen array (mis. f.menerapkan(thisObject, [a, b, c]), bukan f.panggilan(thisObject, a, b, c)). Aku ingin't diuji, jadi mungkin ada perbedaan, tapi itu akan sangat browser tertentu. It's kemungkinan bahwa panggilan lebih cepat jika anda don't sudah memiliki argumen array dan terapkan lebih cepat jika anda melakukannya.

Komentar (0)

Berikut ini's yang baik mnemonic. Arlaku menggunakan Arrays dan Always mengambil satu atau dua Argumen. Ketika anda menggunakan Csemua yang harus anda Cntuk jumlah argumen.

Komentar (2)

Sementara ini adalah topik lama, aku hanya ingin menunjukkan bahwa .panggilan adalah sedikit lebih cepat daripada .berlaku. Saya dapat't memberitahu anda persis mengapa.

Lihat jsPerf, http://jsperf.com/test-call-vs-apply/3


[UPDATE!]

Douglas Crockford menyebutkan secara singkat perbedaan antara keduanya, yang dapat membantu menjelaskan perbedaan kinerja... http://youtu.be/ya4UHuXNygM?t=15m52s

Menerapkan mengambil array argumen, saat Panggilan berlangsung nol atau lebih parameter individu! Ah hah!

.menerapkan(ini, [...])

.call(ini, param1, param2, param3, param4...)

Komentar (5)

Berikut kutipan dari Penutupan: Panduan Definitif oleh Michael Bolin. Mungkin terlihat sedikit panjang, tapi itu's jenuh dengan banyak wawasan. Dari "Lampiran B. Sering Disalahpahami JavaScript Konsep":


Apa yang ini Mengacu pada Saat Fungsi Dipanggil

Ketika memanggil sebuah fungsi dari bentuk foo.bar.baz(), objek foo.bar ini disebut sebagai penerima. Ketika fungsi ini dipanggil, itu adalah receiver yang digunakan sebagai nilai untuk ini:

var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
  for (var i = 0; i < arguments.length; i++) {
    this.value += arguments[i];
  }
  return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);

Jika tidak ada secara eksplisit penerima ketika fungsi dipanggil, maka objek global menjadi penerima. Seperti yang dijelaskan di "goog.global" di halaman 47, jendela objek global ketika JavaScript dijalankan di web browser. Hal ini menyebabkan beberapa perilaku mengejutkan:

var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN

Meskipun obj.addValues dan f mengacu pada fungsi yang sama, mereka berperilaku berbeda ketika disebut karena nilai penerima yang berbeda di setiap panggilan. Untuk alasan ini, ketika memanggil sebuah fungsi yang mengacu pada ini, itu adalah penting untuk memastikan bahwa ini akan memiliki nilai yang benar ketika dipanggil. Untuk menjadi jelas, jika ini yang tidak disebutkan dalam fungsi tubuh, maka perilaku f(20) dan obj.addValues(20) akan sama.

Karena fungsi kelas objek dalam JavaScript, mereka dapat memiliki metode mereka sendiri. Semua fungsi memiliki metode call() dan berlaku() yang membuatnya mungkin untuk mendefinisikan penerima (yaitu, objek yang ini menunjuk pada) saat memanggil fungsi tersebut. Metode tanda tangan adalah sebagai berikut:

/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;

Perhatikan bahwa satu-satunya perbedaan antara call() dan berlaku() adalah panggilan() menerima parameter fungsi sebagai argumen individu, sedangkan berlaku() menerima mereka sebagai satu array:

// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);

Berikut panggilan yang setara, seperti f dan obj.addValues merujuk kepada fungsi yang sama:

obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);

Namun, karena tidak ada panggilan() atau berlaku() menggunakan nilai sendiri penerima untuk pengganti penerima argumen ketika itu adalah yang tidak ditentukan, berikut tidak akan bekerja:

// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);

Nilai ini tidak dapat null atau undefined ketika fungsi dipanggil. Ketika null atau undefined disediakan sebagai penerima untuk call() atau berlaku(), global objek digunakan sebagai nilai untuk penerima sebaliknya. Oleh karena itu, sebelumnya memiliki kode yang sama efek samping yang tidak diinginkan dari menambahkan sebuah properti bernama nilai untuk objek global.

Mungkin akan membantu untuk berpikir tentang fungsi sebagai tidak memiliki pengetahuan tentang variabel yang ditetapkan. Hal ini membantu memperkuat gagasan bahwa nilai ini akan terikat ketika fungsi ini dipanggil daripada ketika didefinisikan.


Akhir dari ekstrak.

Komentar (2)

Hal ini berguna di kali untuk satu objek untuk meminjam fungsi dari objek lain, yang berarti bahwa pinjaman objek hanya menjalankan masa prapaskah fungsi seolah-olah itu sendiri.

Kode kecil contoh:

var friend = {
    car: false,
    lendCar: function ( canLend ){
      this.car = canLend;
 }

}; 

var me = {
    car: false,
    gotCar: function(){
      return this.car === true;
  }
};

console.log(me.gotCar()); // false

friend.lendCar.call(me, true); 

console.log(me.gotCar()); // true

friend.lendCar.apply(me, [false]);

console.log(me.gotCar()); // false

Metode ini sangat berguna untuk memberikan benda-benda yang bersifat sementara fungsi.

Komentar (1)

Contoh lain dengan Panggilan, Berlaku dan Mengikat. Perbedaan antara Panggilan dan Menerapkan jelas, tapi Mengikat bekerja seperti ini:

  1. Mengikat mengembalikan sebuah instance dari sebuah fungsi yang dapat dijalankan
  2. Parameter pertama adalah 'ini'
  3. Parameter kedua adalah Koma daftar argumen (seperti Panggilan)

}

function Person(name) {
    this.name = name; 
}
Person.prototype.getName = function(a,b) { 
     return this.name + " " + a + " " + b; 
}

var reader = new Person('John Smith');

reader.getName = function() {
   // Apply and Call executes the function and returns value

   // Also notice the different ways of extracting 'getName' prototype
   var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
   console.log("Apply: " + baseName);

   var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy"); 
   console.log("Call: " + baseName);

   // Bind returns function which can be invoked
   var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
   console.log("Bind: " + baseName());
}

reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/
Komentar (0)

I'd ingin menunjukkan sebuah contoh, dimana 'valueForThis' argumen yang digunakan:

Array.prototype.push = function(element) {
   /*
   Native code*, that uses 'this'       
   this.put(element);
   */
}
var array = [];
array.push(1);
array.push.apply(array,[2,3]);
Array.prototype.push.apply(array,[4,5]);
array.push.call(array,6,7);
Array.prototype.push.call(array,8,9);
//[1, 2, 3, 4, 5, 6, 7, 8, 9] 

*rincian: http://es5.github.io/#x15.4.4.7

Komentar (0)

Call() mengambil koma-dipisahkan argumen, ex:

.panggilan(ruang lingkup, arg1, arg2, arg3)

dan menerapkan() mengambil sebuah array argumen, ex:

.menerapkan(ruang lingkup, [arg1, arg2, arg3])

berikut ini adalah beberapa contoh penggunaan: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/

Komentar (1)

Dari MDN docs pada Fungsi.prototipe.berlaku() :

menerapkan metode() memanggil fungsi dengan diberikan ini nilai dan argumen-argumen yang diberikan sebagai array (atau array-seperti objek).

Sintaks

menyenangkan.menerapkan(thisArg, [argsArray])

Dari MDN docs pada Fungsi.prototipe.call() :

panggilan() method ini memanggil fungsi dengan diberikan ini nilai dan argumen yang diberikan secara individual.

Sintaks

menyenangkan.panggilan(thisArg[, arg1[, arg2[, ...]]])

Dari Fungsi.menerapkan dan Fungsi.panggilan di JavaScript :

berlaku() metode ini identik dengan panggilan(), kecuali berlaku() membutuhkan array sebagai parameter kedua. Array merupakan argumen untuk metode target.


Contoh kode :

var doSomething = function() {
    var arr = [];
    for(i in arguments) {
        if(typeof this[arguments[i]] !== 'undefined') {
            arr.push(this[arguments[i]]);
        }
    }
    return arr;
}

var output = function(position, obj) {
    document.body.innerHTML += '<h3>output ' + position + '</h3>' + JSON.stringify(obj) + '\n<br>\n<br><hr>';
}

output(1, doSomething(
    'one',
    'two',
    'two',
    'one'
));

output(2, doSomething.apply({one : 'Steven', two : 'Jane'}, [
    'one',
    'two',
    'two',
    'one'
]));

output(3, doSomething.call({one : 'Steven', two : 'Jane'},
    'one',
    'two',
    'two',
    'one'
));

Lihat juga [ini Biola][4].

Komentar (0)

Perbedaan mendasar adalah bahwa call() menerima daftar argumen, sementara berlaku() menerima satu array argumen.

Komentar (1)

Berikut ini's kecil-ish posting, saya menulis tentang hal ini:

http://sizeableidea.com/call-versus-apply-javascript/

var obj1 = { which : "obj1" },
obj2 = { which : "obj2" };

function execute(arg1, arg2){
    console.log(this.which, arg1, arg2);
}

//using call
execute.call(obj1, "dan", "stanhope");
//output: obj1 dan stanhope

//using apply
execute.apply(obj2, ["dan", "stanhope"]);
//output: obj2 dan stanhope

//using old school
execute("dan", "stanhope");
//output: undefined "dan" "stanhope"
Komentar (1)

Perbedaannya adalah bahwa call() mengambil argumen fungsi secara terpisah, dan berlaku() mengambil argumen fungsi dalam array.

Komentar (0)

Kita dapat membedakan panggilan dan menerapkan metode seperti di bawah ini

CALL : fungsi dengan argumen menyediakan secara individual. Jika anda tahu argumen untuk diteruskan atau tidak ada argumen untuk lulus anda dapat menggunakan panggilan.

BERLAKU : Memanggil fungsi dengan argumen yang disediakan sebagai array. Anda dapat menggunakan terapkan jika anda don't tahu berapa banyak argumen yang akan lolos ke fungsi.

Ada keuntungan menggunakan berlaku selama panggilan, kami don't perlu untuk mengubah jumlah argumen hanya kita dapat mengubah sebuah array yang dilewatkan.

Tidak ada perbedaan besar dalam kinerja. Tetapi kita dapat mengatakan panggilan adalah sedikit lebih cepat dibandingkan untuk menerapkan karena array perlu mengevaluasi dalam menerapkan metode.

Komentar (0)

Perbedaan antara kedua metode ini adalah, bagaimana anda ingin untuk melewatkan parameter.

"Untuk sebuah array dan C untuk koma" adalah berguna mnemonic.

Komentar (1)

Panggilan dan berlaku baik digunakan untuk memaksa ini nilai saat fungsi dijalankan. Satu-satunya perbedaan adalah bahwa panggilan mengambil n+1 argumen di mana 1 adalah ini dan &#39;n&#39; argumen. terapkan hanya membutuhkan dua argumen, salah satunya adalah ini yang lain adalah argumen array.

Keuntungan yang saya lihat di berlaku atas panggilan adalah bahwa kita dapat dengan mudah mendelegasikan fungsi yang memanggil fungsi lain tanpa banyak usaha;

function sayHello() {
  console.log(this, arguments);
}

function hello() {
  sayHello.apply(this, arguments);
}

var obj = {name: 'my name'}
hello.call(obj, 'some', 'arguments');

Mengamati bagaimana dengan mudah kita didelegasikan hello untuk sayHello menggunakan berlaku, tapi dengan call ini sangat sulit untuk mencapai.

Komentar (0)

Meskipun call dan terapkan mencapai hal yang sama, saya pikir ada minimal satu tempat di mana anda tidak dapat menggunakan panggilan, tapi hanya dapat menggunakan terapkan. Itu adalah ketika anda ingin mendukung warisan dan ingin memanggil konstruktor.

Berikut ini adalah fungsi memungkinkan anda untuk membuat kelas-kelas yang juga mendukung menciptakan kelas-kelas dengan memperluas kelas-kelas lain.

function makeClass( properties ) {
    var ctor = properties['constructor'] || function(){}
    var Super = properties['extends'];
    var Class = function () {
                 // Here 'call' cannot work, only 'apply' can!!!
                 if(Super)
                    Super.apply(this,arguments);  
                 ctor.apply(this,arguments);
                }
     if(Super){
        Class.prototype = Object.create( Super.prototype );
        Class.prototype.constructor = Class;
     }
     Object.keys(properties).forEach( function(prop) {
           if(prop!=='constructor' && prop!=='extends')
            Class.prototype[prop] = properties[prop];
     });
   return Class; 
}

//Usage
var Car = makeClass({
             constructor: function(name){
                         this.name=name;
                        },
             yourName: function() {
                     return this.name;
                   }
          });
//We have a Car class now
 var carInstance=new Car('Fiat');
carInstance.youName();// ReturnsFiat

var SuperCar = makeClass({
               constructor: function(ignore,power){
                     this.power=power;
                  },
               extends:Car,
               yourPower: function() {
                    return this.power;
                  }
              });
//We have a SuperCar class now, which is subclass of Car
var superCar=new SuperCar('BMW xy',2.6);
superCar.yourName();//Returns BMW xy
superCar.yourPower();// Returns 2.6
Komentar (1)

Perbedaan utama adalah, menggunakan call, kita dapat mengubah lingkup dan melewati argumen seperti biasa, tapi menerapkan memungkinkan anda menelepon menggunakan argumen sebagai Array (lulus mereka sebagai array). Tetapi dalam hal apa yang mereka lakukan dalam kode anda, mereka cukup mirip.

Sedangkan sintaks dari fungsi ini adalah hampir identik dengan yang berlaku(), perbedaan mendasar adalah bahwa panggilan() menerima sebuah argumen klik disini, sementara yang berlaku() menerima single array argumen.

Jadi seperti yang anda lihat, tidak ada perbedaan besar, tapi masih ada kasus-kasus yang kita sukai menggunakan panggilan() atau berlaku(). Untuk contoh, lihat kode di bawah ini, yang menemukan terkecil dan terbesar dalam array dari MDN, menggunakan terapkan metode:

// min/max number in an array
var numbers = [5, 6, 2, 3, 7];

// using Math.min/Math.max apply
var max = Math.max.apply(null, numbers); 
// This about equal to Math.max(numbers[0], ...)
// or Math.max(5, 6, ...)

var min = Math.min.apply(null, numbers)

Jadi perbedaan utama adalah hanya cara kita menyampaikan argumen:

Hubungi:

function.call(thisArg, arg1, arg2, ...);

Berlaku:

function.apply(thisArg, [argsArray]);
Komentar (0)

Penjelasan:

Kedua call() dan berlaku() adalah metode yang terletak di Fungsi.prototipe. Oleh karena itu mereka tersedia pada setiap fungsi objek melalui prototipe rantai. Kedua call() dan berlaku() dapat menjalankan fungsi dengan nilai tertentu dari ini.

Perbedaan utama antara call() dan berlaku() adalah cara yang anda harus lulus dalam argumen ke dalamnya. Dalam kedua call() dan berlaku() anda lulus sebagai argumen pertama objek yang anda ingin menjadi nilai seperti ini. Argumen lain yang berbeda dengan cara sebagai berikut:

  • Dengan call() anda harus dimasukkan ke dalam argumen-argumen yang biasanya (mulai dari argumen kedua)
  • Dengan berlaku() anda harus lulus dalam array argumen.

Contoh:

let obj = {
  val1: 5,
  val2: 10
}

const summation = function (val3, val4) {
  return  this.val1 + this.val2 + val3 + val4;
}

console.log(summation.apply(obj, [2 ,3]));
// first we assign we value of this in the first arg
// with apply we have to pass in an array

console.log(summation.call(obj, 2, 3));
// with call we can pass in each arg individually

Mengapa saya perlu menggunakan fungsi-fungsi ini?

Yang ini nilai dapat sulit kadang-kadang dalam javascript. Nilai ini ditentukan ketika fungsi ini tidak dieksekusi ketika suatu fungsi didefinisikan. Jika fungsi kita adalah dependend pada kanan ini mengikat kita dapat menggunakan call() dan berlaku() untuk menegakkan perilaku ini. Misalnya:

var name = 'unwantedGlobalName';

const obj =  {
  name: 'Willem',
  sayName () { console.log(this.name);}
}

let copiedMethod = obj.sayName;
// we store the function in the copiedmethod variable

copiedMethod();
// this is now window, unwantedGlobalName gets logged

copiedMethod.call(obj);
// we enforce this to be obj, Willem gets logged
Komentar (0)