Heim  >  Artikel  >  Web-Frontend  >  Funktionsspeicher von JavaScript-Lernnotizen

Funktionsspeicher von JavaScript-Lernnotizen

韦小宝
韦小宝Original
2018-01-25 11:03:041566Durchsuche

Dieser Artikel stellt hauptsächlich den Funktionsspeicher von JavaScript vor. Der Herausgeber findet ihn recht gut. Jetzt werde ich den JavaScript-Quellcode mit Ihnen teilen und ihn als Referenz geben. Wenn Sie sich für JavaScript interessieren, folgen Sie bitte dem Editor, um einen Blick darauf zu werfen

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

Definition

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

Zum Beispiel:

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

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

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

Prinzip

Eine solche Merkfunktion lässt sich im Prinzip nur von Ihnen umsetzen Sie müssen die Parameter mit den entsprechenden Ergebnisdaten kombinieren. Beim Aufruf wird beurteilt, ob die dem Parameter entsprechenden Daten vorhanden sind, und die entsprechenden Ergebnisdaten werden zurückgegeben.

Erste Version

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 die Funktion „Memory“ nicht 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. Dabei wird im Wesentlichen die räumliche Komplexität des Algorithmus im Austausch für eine bessere Zeitkomplexität des Codes in der JavaScript-Ausführungszeit geopfert wird zu einem Engpass, daher ist dieser Ansatz, Platz für Zeit zu opfern, um die Effizienz der Programmausführung zu verbessern, in den meisten Szenarien 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 verifizieren:

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. Schauen wir uns also an, wie die Memoize-Funktion von Underscore implementiert ist:

// 第二版 (来自 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 hervorgeht, verwendet der Unterstrich standardmäßig den ersten Parameter der Funktion als Schlüssel. Wenn Sie also

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

var memoizedAdd = memorize(add)

memoizedAdd(1, 2, 3) // 6
memoizedAdd(1, 2, 4) // 6
direkt verwenden, liegt definitiv ein Problem vor, wenn Sie 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 gespeichert wird, was der String nach dem

-Objekt ist ist serialisiert .

Anwendbare Szenarien

Wir nehmen 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 endgültige Zä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 Gesamtanzahl 12 Mal beträgt. Aufgrund der Verwendung des Funktionsspeichers wird die Anzahl der Aufrufe von 453 Mal auf 12 Mal reduziert!

Vergessen Sie nicht, während Sie aufgeregt sind. Denken Sie: 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!

Vielleicht haben Sie das Gefühl, dass Fibonacci in der täglichen Entwicklung nicht verwendet wird, und dieses Beispiel scheint wenig praktischen Wert zu haben. Tatsächlich wird dieses Beispiel verwendet, um ein Verwendungsszenario zu veranschaulichen, das heißt, wenn es eine große Anzahl von Wiederholungen gibt sind erforderlich. Für Berechnungen oder wenn 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.

Verwandte Empfehlungen:

Analyse der Bindungsnutzung von JavaScript-Funktionen

Detaillierte Erläuterung der Drosselung und Anti-Shake-Entprellung der JavaScript-Funktion

Erklären Sie die Verwendung der JavaScript-Funktionsbindung anhand von Beispielen

Das obige ist der detaillierte Inhalt vonFunktionsspeicher von JavaScript-Lernnotizen. 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