Koks skirtumas tarp skambučio ir programos?

Koks skirtumas tarp call ir kreipimosi į funkciją?

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

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

Ar yra kokių nors skirtumų tarp pirmiau minėtų dviejų metodų? Kada geriausia naudoti call ir atvirkščiai?

2834
31 дек. nustatė John Duff gruodžio 31 d 2009-12-31 22:56 '10 10:56 val. 2009-12-31 22:56
@ 20 atsakymų

Skirtumas yra tas, kad apply leidžia jums skambinti funkcija su arguments kaip masyvas; reikalauja, kad parametrai būtų aiškiai nurodyti. Naudinga mnemoninė „ A, skirta Rray “ir„ C “,„ C “.

Žiūrėkite MDN dokumentaciją ir kreipkitės .

Pseudo-sintaksė:

theFunction.apply(valueForThis, arrayOfArgs)

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

ES6 taip pat yra galimybė spread masyvą naudoti su call funkcija, čia galite matyti suderinamumą.

Kodo pavyzdys:

3398
31 дек. atsakymas pateikiamas standartiniu gruodžio 31 d. 2009-12-31 23:00 '10 23:00 val. 2009-12-31 23:00

K. Scott Allen yra geras įrašas .

Iš esmės jie skiriasi tuo, kaip jie tvarko funkcijų argumentus.

Taikymo () metodas yra identiškas kvietimui (), išskyrus atvejus, kai taikomas () reikalaujama, kad kaip antrasis parametras būtų naudojamas masyvas. Masyvas atspindi tikslinio metodo argumentus.

border=0

Taigi:

 // assuming you have f function f(message) { ... } f.call(receiver, "test"); f.apply(receiver, ["test"]); 
214
31 дек. Atsakymas pateikiamas ne gruodžio 31 d. 2009-12-31 22:59 '10, 10:59 val. 2009-12-31 22:59

Jei norite atsakyti į klausimą, kada naudoti kiekvieną funkciją, naudokite, jei nežinote perduodamų argumentų skaičiaus arba jei jie jau yra masyvo ar masyvo tipo objektuose (pvz., Objektas t21> siųsti savo argumentus). call kitaip, nes nėra reikalo apvynioti argumentų masyvo.

 f.call(thisObject, a, b, c); // Fixed number of arguments f.apply(thisObject, arguments); // Forward this function arguments var args = []; while (...) { args.push(some_value()); } f.apply(thisObject, args); // Unknown number of arguments 

Kai neperduodu jokių argumentų (pvz., Jūsų pavyzdys), norėčiau call , nes aš vadinu šią funkciją. apply reiškia, kad jūs naudojate funkciją (nėra) argumentų.

f.apply(thisObject, [a, b, c]) skirtumai neturėtų būti, išskyrus atvejus, kai naudosite taikymą ir nutraukite masyvo argumentus (pvz., f.apply(thisObject, [a, b, c]) vietoj f.call(thisObject, a, b, c) ). Aš jo neišbandžiau, todėl gali būti skirtumų, tačiau tai būtų labai specifinė naršyklėje. Tikriausiai call greičiau, jei masyve neturite jokių argumentų, ir greičiau, jei tai darote.

151
01 янв. Matthew Crumley atsakymas 2010-01-01 00:50 '10 - 0:50 2010-01-01 00:50

Čia yra gera mnemonija. Pply naudojimas Rrays“ ir „ A“ visada turi vieną ar du argumentus. Kai naudojate C, jums reikia C , nurodykite argumentų skaičių.

103
04 сент. atsakymas pateikiamas Joe 04 sep. 2013-09-04 16:36 '13, 16:36, 2013-09-04 16:36

Nors tai yra senas klausimas, tik norėjau pabrėžti, kad .call yra šiek tiek greičiau nei .apply. Aš negaliu tiksliai pasakyti, kodėl.

Žr. JsPerf, http://jsperf.com/test-call-vs-apply/3


[ UPDATE! ]

Douglasas Crockfordas trumpai paminėja skirtumą tarp šių dviejų, kurie gali padėti paaiškinti skirtumus tarp rezultatų ... http://youtu.be/ya4UHuXNygM?t=15m52s

Taikyti atsižvelgia į daugybę argumentų, o skambutis - nulis arba daugiau atskirų parametrų! Ah, ha!

.apply(this, [...])

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

91
07 нояб. Atsakymas pateikiamas kmatheny 07.11 . 2011-11-07 20:36 '11 ne 20:36 2011-11-07 20:36

Toliau pateikiamas Michaelo Bolino knygos „Uždarymo: pilno vadovo“ ištrauka. Tai gali atrodyti šiek tiek ilgai, bet ji įnešė daug įžvalgų. Iš „B priedėlio„ JavaScript “sąvokos, kurios dažnai yra neteisingai suprantamos:


this reiškia, kai funkcija vadinama

Skambinant foo.bar.baz() formos funkcija, objektas foo.bar vadinamas imtuvu. Kai funkcija vadinama, tai yra imtuvas, kuris yra naudojamas kaip šios vertės:

 var obj = {}; obj.value = 10;  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); 

Jei nėra skubaus gavėjo, kai funkcija vadinama, pasaulinis objektas tampa gavėju. Kaip paaiškinta „goog.global“ puslapyje 47, >

 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 

Nors obj.addValues ir f nurodo tą pačią funkciją, skambinant jie elgiasi kitaip, nes gavėjo vertė skiriasi nuo kiekvieno skambučio. Dėl šios priežasties, kai skambinate tai nurodančiai funkcijai, svarbu užtikrinti, kad skambinant tai būtų tinkama vertė. Aiškumo sumetimais, jei this nebuvo nuoroda į funkcijų kūną, tada f(20) ir obj.addValues(20) elgesys būtų tas pats.

Kadangi funkcijos „JavaScript“ yra pirmos klasės objektai, jie gali turėti savo metodus. Visose funkcijose yra call() ir apply() metodai, kurie leidžia jums perrašyti gavėją (t. Y. Objektą, kuriam this ), kai skambinama. Metodo parašai yra tokie:

  Function.prototype.call;  Function.prototype.apply; 

Atkreipkite dėmesį, kad vienintelis skirtumas tarp call() ir apply() yra tas, kad call() perkelia funkcijos parametrus kaip atskirus argumentus, o apply() juos gauna kaip vieną masyvą:

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

Šie skambučiai yra lygiaverčiai, nes f ir obj.addValues nurodo tą pačią funkciją:

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

Tačiau, kadangi nei call() nei apply() nenaudoja savo gavėjo vertės, kad pakeistų gavėjo argumentą, kai jis nenurodytas, šie veiksmai neveiks:

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

Ši vertė niekada negali būti null arba undefined kai skambinate funkcijai. Kai pasaulinis objektas naudojamas kaip gavėjas call() arba apply() null arba undefined . Todėl ankstesnis kodas turi tokį patį nepageidaujamą šalutinį poveikį, kaip visuotiniam objektui pridedant turto pavadinimą.

Gali būti naudinga pagalvoti apie funkciją, neturinčią žinių apie kintamąjį, kuriam jis priskirtas. Tai padeda sustiprinti idėją, kad jos vertė bus prijungta, kai funkcija bus vadinama, o ne tada, kai ji yra apibrėžta.


Pranešimo pabaiga.

74
04 дек. Atsakymą pateikė Dominykas Mostauskis. 2013-12-04 15:41 '13, 15:41 2013-12-04 15:41

Kartais naudinga, jei vienas subjektas pasiskolintų kito ūkio subjekto funkciją, o tai reiškia, kad skolinanti įmonė paprasčiausiai atlieka paskolos teikimo funkciją, tarsi ji būtų pati.

Mažo kodo pavyzdys:

 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 

Šie metodai yra labai naudingi teikiant laikinus objektus objektams.

33
25 февр. atsakymas pateikiamas tjacks3 25 vasaris 2014-02-25 22:31 '14, 10:31 pm 2014-02-25 22:31

Kitas pavyzdys yra skambutis, taikymas ir susiejimas. Skirtumas tarp skambučio ir taikymo yra akivaizdus, ​​tačiau „ Bind“ veikia taip:

  • „Bind“ grąžina funkciją, kurią galima atlikti.
  • Pirmasis parametras yra „tai“
  • Antrasis parametras yra kableliais atskirtas argumentų sąrašas (pvz., Skambutis)

}

 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();  
24
31 марта '15 в 10:32 2015-03-31 10:32 atsakymas pateikiamas „ Mahesh“ kovo 31 d. 15 val. 10:32 2015-03-31 10:32

Norėčiau parodyti pavyzdį, kai naudojamas šis argumentas:

 Array.prototype.push = function(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] 

** daugiau informacijos: http://es5.github.io/#x15.4.4.7 *

22
05 июля '13 в 13:56 2013-07-05 13:56 atsakymą pateikė user669677 liepos 05 '13, 13:56 2013-07-05 13:56

Kvietimas () sutinka su kableliais atskirtais argumentais:

.call(scope, arg1, arg2, arg3)

ir taikyti () turi daugybę argumentų, pvz .:

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

Štai keletas naudojimo pavyzdžių: http://blog.i-evaluation.com/2012/08/15/javascript-call-and-apply/

20
21 янв. Atsakymas, kurį pateikė Mark Karwowski Jan 21 2014-01-21 21:11 '14, 21:11 2014-01-21 21:11

MDN dokumentų į „Function.prototype.apply“ () :

Taikymo () metodas vadina funkciją su nurodyta reikšme ir argumentais, pateiktais kaip masyvas (arba masyvo tipo objektas).

Sintaksė

 fun.apply(thisArg, [argsArray]) 

MDN dokumentų į „Function.prototype.call“ () :

Skambučio () metodas vadina funkciją su pateikta verte ir atskirai pateiktais argumentais.

Sintaksė

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

Function.apply“ ir „Function.call“ sistemoje „JavaScript“ :

Taikymo () metodas yra identiškas kvietimui (), išskyrus atvejus, kai taikomas () reikalingas masyvas kaip antrasis parametras. Masyvas atspindi tikslinio metodo argumentus.


Kodo pavyzdys:

šį scenarijų . 

18
18 янв. John Slegers atsakymas Jan 18 2016-01-18 05:27 '16 at 5:27 am 2016-01-18 05:27

Pagrindinis skirtumas yra tas, kad call() užima argumentų sąrašą ir apply() vieną argumentų masyvą .

11
28 февр. atsakymą pateikė Rakesh Kumar 28 vasaris. 2014-02-28 07:57 '14 at 7:57 2014-02-28 07:57

Štai mažas pranešimas, apie kurį parašiau:

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
04 дек. atsakymas duotas Dan 04 d. 2013-12-04 16:58 '13, 16:58, 2013-12-04 16:58

Skirtumas yra tas, kad call() užfiksuoja funkcijų argumentus atskirai ir apply() argumentus, susijusius su masyvo funkcija.

7
11 авг. atsakymas, kurį pateikė Sanjib Debnath 11 rug . 2016-08-11 12:25 '16 at 12:25 2016-08-11 12:25

Mes galime diferencijuoti raginimo ir taikymo metodus, kaip parodyta žemiau.

CALL: Funkcija su argumentu pateikiama atskirai. Jei žinote argumentus, kurie turi būti perduoti, ar ne perduodami argumentai, galite naudoti skambutį.

APPLY: funkcijos skambutis su argumentu, pateiktu kaip masyvas. Galite naudoti, jei nežinote, kiek argumentų bus perduota funkcijai.

Yra pranašumas naudojant per skambučio programą, mums nereikia keisti argumentų skaičiaus, mes galime pakeisti perduotą masyvą.

Nėra didelių skirtumų. Tačiau galime pasakyti, kad skambinimas bitui yra greitesnis nei palyginimas, nes masyvas turi būti įvertintas taikant taikomąjį metodą.

6
06 нояб. Atsakymas pateikiamas Praveen D 06 lapkričio. 2013-11-06 14:50 '13, 14:50, 2013-11-06 14:50

Šių metodų skirtumas yra tas, kaip norite perduoti parametrus.

„A masyvui ir C kablui“ yra patogus mnemoninis.

5
03 авг. atsakymą pateikė venkat7668 03 rug . 2015-08-03 09:15 '15 at 9:15 am 2015-08-03 09:15

Skambinimas ir abiejų naudojimas yra naudojamas norint priversti this vertę, kai funkcija yra vykdoma. Vienintelis skirtumas yra tas, kad call užima argumentus n+1 , kur 1 yra this ir 'n' arguments . apply trunka tik du argumentus, vienas - this , kitas yra argumentų masyvas.

Privalumas, kurį matau per call yra tai, kad mes galime lengvai perduoti funkcijų skambutį kitai funkcijai be didelių pastangų;

 function sayHello() { console.log(this, arguments); } function hello() { sayHello.apply(this, arguments); } var obj = {name: 'my name'} hello.call(obj, 'some', 'arguments'); 

Atkreipkite dėmesį, kaip paprasta sayHello Naudokitės“, bet su call tai yra labai sunku pasiekti.

5
24 нояб. Atsakymą pateikė Raghavendra lapkričio 24 d. 2015-11-24 11:36 '15, 11:36, 2015-11-24 11:36

Net jei call ir taikote tą patį, manau, kad bent viena vieta, kurioje negalite naudoti call , bet gali būti naudojama tik. Tai yra tada, kai norite palaikyti paveldėjimą ir norite paskambinti konstruktoriui.

Čia yra funkcija, leidžianti sukurti klases, kurios taip pat palaiko klasių kūrimą, praplečiant kitas klases.

 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
12 февр. Atsakymą pateikė Dhana Krishnasamy vasario 12 d. 2015-02-12 21:10 '15, 21:10 2015-02-12 21:10

Pagrindinis skirtumas yra tas, kad naudojant skambutį galime pakeisti plotą ir perduoti argumentus kaip įprasta, tačiau taikymas leidžia jums jį skambinti naudojant argumentus kaip masyvą (perduoti juos kaip masyvą). Tačiau kalbant apie tai, ką jie turėtų daryti savo kode, jie yra gana panašūs.

Nors šios funkcijos sintaksė yra beveik identiška taikymo () metodo sintaksei, pagrindinis skirtumas yra tas, kad skambutis () užima argumentų sąrašą ir taiko () vieną argumentų masyvą.

Taigi, kaip matote, nėra daug skirtumų, tačiau vis dar yra atvejų, kai mes norėtume naudoti skambutį () arba taikyti (). Pavyzdžiui, peržiūrėkite žemiau esantį kodą, kuriame randamas mažiausias ir didžiausias MDN masyvo skaičius naudojant taikomąjį metodą:

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

Taigi pagrindinis skirtumas yra tas, kaip perduodame argumentus:

Skambinkite:

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

Taikyti:

 function.apply(thisArg, [argsArray]); 
3
11 мая '17 в 17:35 2017-05-11 17:35 atsakymą Alireza davė gegužės 17 d., 17 val. 17:35 2017-05-11 17:35

Santrauka:

Abu call() ir apply() yra „ Function.prototype būdai. Todėl jie yra prieinami kiekvienam funkcijų objektui per prototipų grandinę. Tiek call() ir apply() gali atlikti funkciją su nurodyta verte.

Pagrindinis skirtumas tarp call() ir apply() yra būdas, kuriuo argumentai perduodami. Abiejuose call() ir apply() pereinate kaip pirmąjį argumentą tokiam objektui, kurį norite būti verte, kaip this . Kiti argumentai skiriasi taip:

  • call() turite įvesti argumentus kaip įprasta (pradedant nuo antrojo argumento)
  • Taikydami apply() turite perduoti argumentų rinkinį.

Pavyzdys:

 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
29 авг. Atsakymą pateikė Willem van der Veen rugpjūčio 29 d. 2018-08-29 18:29 '18, 18:29 pm 2018-08-29 18:29

Kiti klausimai apie „ žymių arba Užduoti klausimą