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?
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
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"]);
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.
SEBUAH Ply menggunakanarray dan Selalu mengambil satu atau dua argumen. Saat Anda menggunakanc Semua yang kamu harusc Ount jumlah argumen. C
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...)
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":
this
Merujuk Ketika Suatu Fungsi DipanggilSaat 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.
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.
Contoh lain dengan Call, Apply dan Bind. Perbedaan antara Panggilan dan Terapkan jelas, tetapi Bind berfungsi seperti ini:
}
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
*/
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 *
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/
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.
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 .
Perbedaan mendasar adalah bahwa call()
menerima daftar argumen argumen , sedangkan apply()
menerima array argumen tunggal .
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"
Perbedaannya adalah call()
mengambil argumen fungsi secara terpisah, dan apply()
mengambil argumen fungsi dalam array.
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.
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.
Perbedaan antara metode ini adalah, bagaimana Anda ingin melewatkan parameter.
"A untuk array dan C untuk koma" adalah mnemonic yang praktis.
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
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]);
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:
call()
Anda harus memasukkan argumen secara normal (mulai dari argumen kedua)apply()
Anda harus memberikan argumen.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
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