Heim  >  Artikel  >  Web-Frontend  >  Einführung in JavaScript-Funktionen

Einführung in JavaScript-Funktionen

巴扎黑
巴扎黑Original
2017-09-07 10:24:311298Durchsuche

In diesem Artikel wird hauptsächlich der Funktionsspeicher von JavaScript-Lernnotizen vorgestellt. Der Herausgeber findet ihn recht gut, daher werde ich ihn jetzt mit Ihnen teilen und als Referenz verwenden. Kommen Sie und schauen Sie sich den Editor an

Dieser Artikel erklärt die Implementierung des Funktionsspeichers und der Fibonacci-Sequenz und teilt sie mit allen. Die Details sind wie folgt

Definition

Funktionsspeicher bezieht sich auf das Zwischenspeichern des letzten Berechnungsergebnisses. Wenn beim nächsten Aufruf dieselben Parameter angetroffen werden, werden die Daten im Cache direkt zurückgegeben.

Zum Beispiel:


function add(a, b) {
  return a + b;
}

// 假设 memorize 可以实现函数记忆
var memoizedAdd = memorize(add);

memoizedAdd(1, 2) // 3
memoizedAdd(1, 2) // 相同的参数,第二次调用时,从缓存中取出数据,而非重新计算一次

Prinzip

Es ist sehr einfach, so etwas umzusetzen Eine Speicherfunktion ist einfach. Im Prinzip müssen Sie nur die Parameter und die entsprechenden Ergebnisdaten in einem Objekt speichern. Stellen Sie beim Aufruf fest, ob die dem Parameter entsprechenden Daten vorhanden sind, und geben Sie die entsprechenden Ergebnisdaten zurück, falls vorhanden.

Erste Ausgabe

Lass uns eine Version schreiben:


// 第一版 (来自《JavaScript权威指南》)
function memoize(f) {
  var cache = {};
  return function(){
    var key = arguments.length + Array.prototype.join.call(arguments, ",");
    if (key in cache) {
      return cache[key]
    }
    else return cache[key] = f.apply(this, arguments)
  }
}

Lass es uns testen:


var add = function(a, b, c) {
 return a + b + c
}

var memoizedAdd = memorize(add)

console.time('use memorize')
for(var i = 0; i < 100000; i++) {
  memoizedAdd(1, 2, 3)
}
console.timeEnd(&#39;use memorize&#39;)

console.time(&#39;not use memorize&#39;)
for(var i = 0; i < 100000; i++) {
  add(1, 2, 3)
}
console.timeEnd(&#39;not use memorize&#39;)

In Chrome dauert die Verwendung von „Memory“ etwa 60 ms. Wenn wir keinen Funktionsspeicher verwenden, dauert es etwa 1,3 ms.

Hinweis

Was, wir haben die scheinbar fortschrittliche Funktion Speicher verwendet, aber es stellte sich heraus, dass sie zeitaufwändiger war, in diesem Beispiel fast 60 Mal!

Das Funktionsgedächtnis ist also nicht allmächtig. Wenn Sie sich dieses einfache Szenario ansehen, ist es tatsächlich nicht für das Funktionsgedächtnis geeignet.

Es ist zu beachten, dass der Funktionsspeicher nur eine Programmiertechnik ist, die im Wesentlichen die räumliche Komplexität des Algorithmus im Austausch für eine bessere Zeitkomplexität opfert. In clientseitigem JavaScript wird die Ausführungszeitkomplexität des Codes häufig erhöht Engpass, daher ist in den meisten Szenarien dieser Ansatz, Platz für Zeit zu opfern, um die Effizienz der Programmausführung zu verbessern, sehr wünschenswert.

Zweite Version

Da die erste Version die Join-Methode verwendet, können wir leicht denken, dass die toString-Methode automatisch ausgeführt wird, wenn der Parameter ein Objekt ist namens Konvertieren Sie es in [Objektobjekt] und verketten Sie dann die Zeichenfolge als Schlüsselwert. Schreiben wir eine Demo, um dieses Problem zu überprüfen:


var propValue = function(obj){
  return obj.value
}

var memoizedAdd = memorize(propValue)

console.log(memoizedAdd({value: 1})) // 1
console.log(memoizedAdd({value: 2})) // 1

Beide geben 1 zurück, was offensichtlich ein Problem darstellt. Sehen wir uns also an, wie die Memoize-Funktion von Underscore funktioniert. Implementiert:


// 第二版 (来自 underscore 的实现)
var memorize = function(func, hasher) {
  var memoize = function(key) {
    var cache = memoize.cache;
    var address = &#39;&#39; + (hasher ? hasher.apply(this, arguments) : key);
    if (!cache[address]) {
      cache[address] = func.apply(this, arguments);
    }
    return cache[address];
  };
  memoize.cache = {};
  return memoize;
};

Wie aus dieser Implementierung ersichtlich ist, verwendet der Unterstrich standardmäßig den ersten Parameter der Funktion als Schlüssel. Wenn Sie also

direkt verwenden,

var add = function(a, b, c) {
 return a + b + c
}

var memoizedAdd = memorize(add)

memoizedAdd(1, 2, 3) // 6
memoizedAdd(1, 2, 4) // 6

Es muss ein Problem vorliegen. Wenn wir mehrere Parameter unterstützen möchten, müssen wir die Hasher-Funktion übergeben und den gespeicherten Schlüsselwert anpassen. Daher erwägen wir die Verwendung von JSON.stringify:


var memoizedAdd = memorize(add, function(){
  var args = Array.prototype.slice.call(arguments)
  return JSON.stringify(args)
})

console.log(memoizedAdd(1, 2, 3)) // 6
console.log(memoizedAdd(1, 2, 4)) // 7

Wenn Sie JSON.stringify verwenden, kann auch das Problem gelöst werden, dass der Parameter ein Objekt ist, da das Objekt ein Objekt ist wird nach der Serialisierungszeichenfolge gespeichert.

Anwendbare Szenarien

Nehmen wir die Fibonacci-Folge als Beispiel:


var count = 0;
var fibonacci = function(n){
  count++;
  return n < 2? n : fibonacci(n-1) + fibonacci(n-2);
};
for (var i = 0; i <= 10; i++){
  fibonacci(i)
}

console.log(count) // 453

Wir werden feststellen, dass die Endzählung 453 beträgt, was bedeutet, dass die Fibonacci-Funktion 453 Mal aufgerufen wurde! Vielleicht denken Sie, ich habe gerade eine Schleife bis 10 gemacht, warum wurde es so oft aufgerufen, also analysieren wir es im Detail:

Wenn fib(0) ausgeführt wird, wird es 1 Mal aufgerufen

Bei der Ausführung von fib(1) wird es einmal aufgerufen

Bei der Ausführung von fib(2) entspricht es dieses Mal fib(1) + fib(0) plus fib(2) selbst, insgesamt also 1 + 1 + 1 = 3 Mal

Bei der Ausführung von fib(3) entspricht es dieses Mal fib(2) + fib(1) plus fib(3) selbst, insgesamt 3 + 1 + 1 = 5 Mal

Bei der Ausführung von fib(4) entspricht es diesmal fib(3) + fib(2) plus fib(4) selbst, insgesamt 5 + 3 + 1 = 9 Mal

Wenn fib(5) ausgeführt wird, entspricht es diesmal fib(4) + fib(3) plus fib(5) selbst, insgesamt 9 + 5 + 1 = 15 Mal

Bei der Ausführung von fib(6) entspricht dieses Mal fib(5) + fib(4) plus fib(6) selbst, insgesamt 15 + 9 + 1 = 25 Mal

Bei der Ausführung von fib (7) Diesmal entspricht es fib(6) + fib(5) plus fib(7) selbst, insgesamt 25 + 15 + 1 = 41 Mal

Bei der Ausführung von fib(8) Es entspricht fib(7) + fib(6). Diesmal wird fib(8) selbst hinzugefügt, insgesamt 41 + 25 + 1 = 67 Mal.

Bei der Ausführung von fib(9) entspricht es fib(8) + fib(7) plus fib(9) Diesmal selbst, insgesamt 67 + 41 + 1 = 109 Mal

Wenn fib(10) ausgeführt wird, entspricht es fib(9 ) + fib(8) plus fib(10) selbst dieses Mal, insgesamt 109 + 67 + 1 = 177 Mal
Die Gesamtzahl der Ausführungen beträgt also: 177 + 109 + 67 + 41 + 25 + 15 + 9 + 5 + 3 + 1 + 1 = 453 Mal!

Was wäre, wenn wir das Funktionsgedächtnis verwenden würden?


var count = 0;
var fibonacci = function(n) {
  count++;
  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};

fibonacci = memorize(fibonacci)

for (var i = 0; i <= 10; i++) {
  fibonacci(i)
}

console.log(count) // 12

Wir werden feststellen, dass die endgültige Gesamtzahl der Aufrufe 12 Mal beträgt. Da der Funktionsspeicher verwendet wird, wird die Anzahl der Aufrufe von 453 auf 12 reduziert auf 12 Mal!

Während Sie aufgeregt sind, vergessen Sie nicht zu denken: Warum ist es 12 Mal?

Die Ergebnisse von 0 bis 10 werden jeweils einmal gespeichert. Soll es 11 Mal sein? Hey, woher kommt diese zusätzliche Zeit?

Daher müssen wir uns auch unsere Schreibmethode genau ansehen. In unserer Schreibmethode überschreiben wir tatsächlich die ursprüngliche Fibonacci-Funktion mit der generierten Fibonacci-Funktion. Wenn wir fibonacci(0) ausführen, wird die Funktion einmal ausgeführt ist { 0: 0}, aber wenn wir fibonacci(2) ausführen, führen wir fibonacci(1) + fibonacci(0) aus, da der Wert von fibonacci(0) 0 ist, das Ergebnis von !cache[address] wahr ist und Fibonacci Die Funktion wird erneut ausgeführt. Es stellt sich heraus, dass die zusätzliche Zeit da ist!

Erzählen Sie mir mehr

Vielleicht haben Sie das Gefühl, dass Fibonacci in der täglichen Entwicklung nicht von großem praktischen Wert ist Dieses Beispiel dient zur Veranschaulichung eines Verwendungsszenarios. Wenn also eine große Anzahl wiederholter Berechnungen erforderlich ist oder eine große Anzahl von Berechnungen von vorherigen Ergebnissen abhängt, können Sie die Verwendung des Funktionsspeichers in Betracht ziehen. Und wenn Sie auf eine solche Szene stoßen, werden Sie es wissen.

Das obige ist der detaillierte Inhalt vonEinführung in JavaScript-Funktionen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn