function foo(a) {
if (/* Some condition */) {
// perform task 1
// perform task 3
}
else {
// perform task 2
// perform task 3
}
}
Ich habe eine Funktion, deren Struktur der obigen ähnlich ist. Ich möchte Aufgabe 3 in eine Funktion abstrahieren bar()
, aber ich möchte den Zugriff auf diese Funktion nur im Rahmen von beschränken foo(a)
.
Ist es richtig, auf das Folgende zu wechseln, um das zu erreichen, was ich will?
function foo(a) {
function bar() {
// Perform task 3
}
if (/* Some condition */) {
// Perform task 1
bar();
}
else {
// Perform task 2
bar();
}
}
Wenn das oben Gesagte korrekt ist, wird bar()
es jedes Mal neu definiert, wenn es foo(a)
aufgerufen wird? (Ich mache mir hier Sorgen um die Verschwendung von CPU-Ressourcen.)
javascript
Tamakisquare
quelle
quelle
Antworten:
Ja, was du da hast, ist richtig. Einige Notizen:
bar
wird bei jedem Aufruf der Funktion erstelltfoo
, aber:bar
funktioniert, können einige Engines feststellen, dass sie es "inline" können, wodurch der Funktionsaufruf vollständig entfällt. V8 macht das und ich bin sicher, dass es nicht der einzige Motor ist, der das macht. Natürlich können sie dies nur tun, wenn dies das Verhalten des Codes nicht ändert.bar
die jedes Mal erstellt wurden, variieren stark zwischen den JavaScript-Engines. Wennbar
es trivial ist, variiert es von nicht nachweisbar bis ziemlich klein. Wenn Sie nichtfoo
tausende Male hintereinander anrufen (z. B. von einemmousemove
Handler), würde ich mir darüber keine Sorgen machen. Selbst wenn Sie es sind, würde ich mir nur Sorgen machen, wenn ich ein Problem bei langsameren Motoren sehen würde. Hier ist ein Testfall mit DOM-Operationen , der darauf hindeutet, dass es eine Auswirkung gibt, aber eine triviale (wahrscheinlich vom DOM-Material verwaschen). Hier ist ein Testfall, der eine reine Berechnung durchführt, die eine viel höhere Auswirkung zeigt, aber ehrlich gesagt sprechen wir von einem Unterschied von Mikrosekunden, weil sogar ein Anstieg von 92% auf etwas, das Mikro benötigtSekunden sind immer noch sehr, sehr schnell. Bis / bis Sie einen realen Einfluss gesehen haben, ist es kein Grund zur Sorge.bar
ist nur innerhalb der Funktion zugänglich und hat Zugriff auf alle Variablen und Argumente für diesen Aufruf der Funktion. Dies macht dies zu einem sehr praktischen Muster.quelle
bar
foo
foo
. Wenn Sie nichtfoo
tausende Male hintereinander anrufen (zum Beispiel nicht in einemmousemove
Handler), würde ich mir darüber überhaupt keine Sorgen machen. Beachten Sie auch, dass einige Engines (z. B. V8) den Code ohnehin einbinden und den Funktionsaufruf vollständig eliminieren, vorausgesetzt, dies ändert nichts an dem, was extern erkannt werden kann.bar()
bei jedem Anruf? Würde es auchfoo.prototype.bar
helfen, die Funktion zu definieren?bar
Zugriff auf die Variablen und Argumente für den Aufruf habenfoo
(alles, was Sie möchten, müssen Sie übergeben), was die Dinge etwas komplizieren kann, aber in einer leistungskritischen Situation, in der Sie dies tun Wenn Sie ein tatsächliches Problem gesehen haben, können Sie es so umgestalten, um zu sehen, ob es das Problem löst. Nein, die Verwendungfoo.prototype
würde nicht wirklich helfen (zum einenbar
wäre sie nicht mehr privat).Dafür sind Verschlüsse da.
var foo = (function () { function bar() { // perform task 3 }; function innerfoo (a) { if (/* some cond */ ) { // perform task 1 bar(); } else { // perform task 2 bar(); } } return innerfoo; })();
Innerfoo (ein Verschluss) enthält einen Verweis auf bar und nur ein Verweis auf innerfoo wird von einer anonymen Funktion zurückgegeben, die nur einmal aufgerufen wird, um den Verschluss zu erstellen.
Die Bar ist auf diese Weise von außen nicht zugänglich.
quelle
var foo = (function () { var bar = function () { // perform task 3 } return function (a) { if (/*some condition*/) { // perform task 1 bar(); } else { // perform task 2 bar(); } }; }());
Der Abschluss behält den Umfang des
bar()
enthaltenen Bereichs bei und gibt die neue Funktion von den selbstausführenden anonymen Funktionssätzen zurück, auf die ein sichtbarerer Bereich gesetzt istfoo()
. Die anonyme selbstausführende Funktion wird genau einmal ausgeführt, es gibt also nur einebar()
Instanz, und jede Ausführung vonfoo()
wird sie verwenden.quelle
Ja, das funktioniert gut.
Die innere Funktion wird nicht jedes Mal neu erstellt, wenn Sie die äußere Funktion aufrufen, sondern neu zugewiesen.
Wenn Sie diesen Code testen:
function test() { function demo() { alert('1'); } demo(); demo = function() { alert('2'); }; demo(); } test(); test();
es wird zeigen
1
,2
,1
,2
, nicht1
,2
,2
,2
.quelle
demo()
jedes Maltest()
als Leistungsproblem bezeichnet werden? Kommt es auf die Komplexität von andemo()
?Ich habe ein jsperf erstellt, um verschachtelte vs. nicht verschachtelte und Funktionsausdrücke vs. Funktionsdeklarationen zu testen, und ich war überrascht zu sehen, dass die verschachtelten Testfälle 20x schneller als nicht verschachtelte ausgeführt wurden. (Ich habe entweder das Gegenteil oder vernachlässigbare Unterschiede erwartet).
https://jsperf.com/nested-functions-vs-not-nested-2/1
Dies ist auf Chrome 76, macOS.
quelle