pengembangan-web-mp-pd.com

Apa perbedaan antara panggilan dan melamar?

Apa perbedaan antara menggunakan call dan apply untuk menjalankan fungsi?

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

func.apply(); vs func.call();

Apakah ada perbedaan kinerja antara kedua metode tersebut? Kapan sebaiknya menggunakan call lebih dari apply dan sebaliknya?

2901
John Duff

Perbedaannya adalah bahwa apply memungkinkan Anda memanggil fungsi dengan arguments sebagai array; call mensyaratkan parameter terdaftar secara eksplisit. Mnemonik yang bermanfaat adalah "Auntuk a rray danCuntuk c omma."

Lihat dokumentasi MDN di terapkan dan panggilan .

Sintaks semu:

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

Ada juga, pada ES6, kemungkinan untuk spread array untuk digunakan dengan fungsi call, Anda dapat melihat kompatibilitasnya sini .

Kode sampel:

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
3466
flatline

K. Scott Allen memiliki Langgan yang bagus mengenai masalah ini.

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

Metode apply () identik dengan panggilan (), kecuali apply () membutuhkan array sebagai parameter kedua. Array mewakili argumen untuk metode target. "

Begitu:

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

Untuk menjawab bagian tentang kapan harus menggunakan setiap fungsi, gunakan apply jika Anda tidak tahu jumlah argumen yang akan Anda lewati, atau jika sudah ada dalam array atau objek mirip array (seperti objek arguments untuk meneruskan sendiri argumen. Gunakan call sebaliknya, karena tidak perlu 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 tidak menyampaikan argumen apa pun (seperti contoh Anda), saya lebih suka call karena saya calling fungsinya. apply akan menyiratkan Anda menerapkan fungsi ke argumen (tidak ada).

Seharusnya tidak ada perbedaan kinerja, kecuali mungkin jika Anda menggunakan apply dan membungkus argumen dalam array (mis. f.apply(thisObject, [a, b, c]) bukannya f.call(thisObject, a, b, c)). Saya belum mengujinya, jadi mungkin ada perbedaan, tetapi akan sangat spesifik browser. Kemungkinan call lebih cepat jika Anda belum memiliki argumen dalam array dan apply lebih cepat jika Anda melakukannya.

152
Matthew Crumley

SEBUAH Ply menggunakanarray dan Selalu mengambil satu atau dua argumen. Saat Anda menggunakanSemua yang kamu harusOunt jumlah argumen. C

105
Joe

Walaupun ini adalah topik lama, saya hanya ingin menunjukkan bahwa .call sedikit lebih cepat daripada .apply. Saya tidak bisa memberi tahu 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

Berlaku mengambil array argumen, sementara Panggilan mengambil nol atau lebih parameter individual! Ah hah!

.apply(this, [...])

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

91
kmatheny

Mengikuti ekstrak dari Penutupan: The Definitive Guide oleh Michael Bolin . Ini mungkin terlihat agak panjang, tetapi penuh dengan banyak wawasan. Dari "Lampiran B. Konsep JavaScript yang Sering Disalahpahami":


Apa yang this Merujuk Ketika Suatu Fungsi Dipanggil

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

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 penerima eksplisit ketika suatu fungsi dipanggil, maka objek global menjadi penerima. Seperti yang dijelaskan dalam "goog.global" di halaman 47, jendela adalah objek global ketika JavaScript dieksekusi di browser web. Ini mengarah pada 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 merujuk pada fungsi yang sama, mereka berperilaku berbeda ketika dipanggil karena nilai penerima berbeda dalam setiap panggilan. Untuk alasan ini, ketika memanggil fungsi yang merujuk ke this, penting untuk memastikan bahwa this akan memiliki nilai yang benar ketika dipanggil. Untuk menjadi jelas, jika this tidak direferensikan dalam fungsi tubuh, maka perilaku f(20) dan obj.addValues(20) akan sama.

Karena fungsi adalah objek kelas satu dalam JavaScript, mereka dapat memiliki metode mereka sendiri. Semua fungsi memiliki metode call() dan apply() yang memungkinkan untuk mendefinisikan ulang receiver (mis., Objek yang merujuk this) ketika memanggil fungsi. Tanda tangan metode 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 apply() adalah call() menerima parameter fungsi sebagai argumen individual, sedangkan apply() menerimanya sebagai array tunggal:

// 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]);

Panggilan berikut ini setara, karena f dan obj.addValues merujuk ke fungsi yang sama:

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

Namun, karena call() atau apply() tidak menggunakan nilai receivernya sendiri untuk menggantikan argumen penerima ketika tidak ditentukan, hal-hal berikut tidak akan berfungsi:

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

Nilai this tidak pernah bisa null atau undefined ketika suatu fungsi dipanggil. Ketika null atau undefined diberikan sebagai penerima ke call() atau apply(), objek global digunakan sebagai nilai untuk penerima sebagai gantinya. Oleh karena itu, kode sebelumnya memiliki efek samping yang tidak diinginkan yang sama dengan menambahkan properti bernama value ke objek global.

Mungkin bermanfaat untuk menganggap suatu fungsi sebagai tidak memiliki pengetahuan tentang variabel yang ditugaskan padanya. Ini membantu memperkuat gagasan bahwa nilai ini akan terikat ketika fungsi dipanggil daripada ketika itu didefinisikan.


Akhir ekstrak.

75

Terkadang berguna untuk satu objek untuk meminjam fungsi dari objek lain, yang berarti bahwa objek pinjaman hanya menjalankan fungsi yang dipinjamkan seolah-olah itu adalah miliknya sendiri.

Contoh kode kecil:

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 fungsi sementara objek.

33
tjacks3

Contoh lain dengan Call, Apply dan Bind. Perbedaan antara Panggilan dan Terapkan jelas, tetapi Bind berfungsi seperti ini:

  1. Bind mengembalikan sebuah instance dari fungsi yang dapat dieksekusi
  2. Parameter pertama adalah ' ini '
  3. Parameter kedua adalah Dipisahkan 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
*/
25
Mahesh

Saya ingin menunjukkan contoh, di mana argumen 'valueForThis' 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 *

23
user669677

Panggilan () mengambil argumen yang dipisahkan koma, mis:

.call(scope, arg1, arg2, arg3)

dan apply () mengambil array argumen, mis:

.apply(scope, [arg1, arg2, arg3])

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

20
Mark Karwowski

Dari dokumen MDN pada Function.prototype.apply () :

Metode apply () memanggil fungsi dengan nilai this dan argumen yang diberikan sebagai array (atau objek mirip array).

Sintaksis

fun.apply(thisArg, [argsArray])

Dari dokumen MDN pada Function.prototype.call () :

Metode panggilan () memanggil fungsi dengan nilai this dan argumen yang diberikan secara individual.

Sintaksis

fun.call(thisArg[, arg1[, arg2[, ...]]])

Dari Function.apply dan Function.call di JavaScript :

Metode apply () identik dengan panggilan (), kecuali apply () membutuhkan array sebagai parameter kedua. Array mewakili 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 this Fiddle .

18
John Slegers

Perbedaan mendasar adalah bahwa call() menerima daftar argumen argumen , sedangkan apply() menerima array argumen tunggal .

11
Rakesh Kumar

Ini tulisan kecil, saya menulis tentang 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"
10
Dan

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

7
Sanjib Debnath

Kami dapat membedakan metode panggilan dan menerapkan seperti di bawah ini

PANGGILAN: Fungsi dengan argumen yang disediakan secara individual. Jika Anda tahu argumen yang harus diteruskan atau tidak ada argumen untuk lulus, Anda dapat menggunakan panggilan.

BERLAKU: Memanggil fungsi dengan argumen yang disediakan sebagai array. Anda dapat menggunakan berlaku jika Anda tidak tahu berapa banyak argumen yang akan diteruskan ke fungsi.

Ada keuntungan menggunakan apply over call, kita tidak perlu mengubah jumlah argumen hanya kita bisa mengubah array yang diteruskan.

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

6
Praveen D

Panggilan dan terapkan keduanya digunakan untuk memaksa nilai this ketika suatu fungsi dijalankan. Satu-satunya perbedaan adalah bahwa call mengambil argumen n+1 di mana 1 adalah this dan 'n' arguments. apply hanya membutuhkan dua argumen, satu adalah this yang lain adalah array argumen.

Keuntungan yang saya lihat di apply lebih dari call adalah bahwa kita dapat dengan mudah mendelegasikan pemanggilan fungsi ke 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');

Amati seberapa mudah kita mendelegasikan hello ke sayHello menggunakan apply, tetapi dengan call ini sangat sulit untuk dicapai.

5
Raghavendra

Perbedaan antara metode ini adalah, bagaimana Anda ingin melewatkan parameter.

"A untuk array dan C untuk koma" adalah mnemonic yang praktis.

5
venkat7668

Meskipun call dan apply mencapai hal yang sama, saya pikir ada setidaknya satu tempat di mana Anda tidak dapat menggunakan call tetapi hanya dapat menggunakan apply. Saat itulah Anda ingin mendukung warisan dan ingin memanggil konstruktor.

Berikut adalah fungsi yang memungkinkan Anda untuk membuat kelas yang juga mendukung pembuatan kelas dengan memperluas kelas lainnya.

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
4

Perbedaan utamanya adalah, menggunakan panggilan, kita dapat mengubah ruang lingkup dan meneruskan argumen seperti biasa, tetapi berlaku memungkinkan Anda menyebutnya menggunakan argumen sebagai Array (meneruskannya sebagai array). Tetapi dalam hal apa yang harus mereka lakukan dalam kode Anda, mereka sangat mirip.

Sementara sintaks dari fungsi ini hampir identik dengan yang berlaku (), perbedaan mendasar adalah panggilan itu () menerima daftar argumen, sementara berlaku () menerima satu array argumen.

Jadi seperti yang Anda lihat, tidak ada perbedaan besar, tapi tetap saja, ada beberapa kasus yang kami lebih suka menggunakan panggilan () atau menerapkan (). Misalnya, lihat kode di bawah ini, yang menemukan angka terkecil dan terbesar dalam array dari MDN, menggunakan metode yang berlaku:

// 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 cara kita menyampaikan argumen:

Hubungi:

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

Menerapkan:

function.apply(thisArg, [argsArray]);
3
Alireza

Ringkasan:

Baik call() dan apply() adalah metode yang terletak di Function.prototype. Oleh karena itu mereka tersedia pada setiap objek fungsi melalui rantai prototipe. Baik call() dan apply() dapat menjalankan fungsi dengan nilai tertentu dari this.

Perbedaan utama antara call() dan apply() adalah cara Anda harus memasukkan argumen ke dalamnya. Dalam call() dan apply(), Anda memberikan argumen pertama objek yang Anda inginkan nilainya sebagai this. Argumen lain berbeda dengan cara berikut:

  • Dengan call() Anda harus memasukkan argumen secara normal (mulai dari argumen kedua)
  • Dengan apply() Anda harus memberikan 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 harus menggunakan fungsi-fungsi ini?

Nilai this terkadang rumit dalam javascript. Nilai this ditentukan ketika suatu fungsi dieksekusi bukan ketika suatu fungsi didefinisikan. Jika fungsi kita bergantung pada pengikatan this yang tepat, kita dapat menggunakan call() dan apply() untuk menegakkan perilaku ini. Sebagai contoh:

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
2