Warum verbessert "use strict" die Leistung in diesem Beispiel um das 10-fache?

128

Nach der Frage Erweitern der Leistung von String.prototype bin ich wirklich fasziniert, weil das Hinzufügen "use strict"zu einer String.prototypeMethode die Leistung zehnmal verbessert hat. Die Erklärung von Bergi ist kurz und erklärt es mir nicht. Warum gibt es einen so dramatischen Unterschied zwischen zwei fast identischen Methoden, die sich nur oben unterscheiden "use strict"? Können Sie das genauer und mit der Theorie dahinter erklären?

String.prototype.count = function(char) {
  var n = 0;
  for (var i = 0; i < this.length; i++)
    if (this[i] == char) n++;
  return n;
};

String.prototype.count_strict = function(char) {
  "use strict";
  var n = 0;
  for (var i = 0; i < this.length; i++)
    if (this[i] == char) n++;
  return n;
};
// Here is how I measued speed, using Node.js 6.1.0

var STR = '0110101110010110100111010011101010101111110001010110010101011101101010101010111111000';
var REP = 1e4;

console.time('proto');
for (var i = 0; i < REP; i++) STR.count('1');
console.timeEnd('proto');

console.time('proto-strict');
for (var i = 0; i < REP; i++) STR.count_strict('1');
console.timeEnd('proto-strict');

Ergebnis:

proto: 101 ms
proto-strict: 7.5 ms
exebook
quelle
1
Können Sie einen Test mit machen this[i] === charund sehen, ob Sie den gleichen Unterschied bekommen?
Niet the Dark Absol
1
Ich habe mit this[i] === charin einer DOM-Umgebung getestet und das Ergebnis ist das gleiche
Cristian Traìna
2
Die Erklärung von bergi besagt, dass beim Aufrufen der countFunktion der thisParameter in ein Zeichenfolgenobjekt anstatt in ein Zeichenfolgenliteral umgewandelt werden muss, während dies im strengen Modus nicht erforderlich ist, um ordnungsgemäß zu funktionieren. Warum dies der Fall ist, ist mir ein Rätsel. Die Antwort interessiert mich sehr.
Nick Larsen
3
@ NickLarsen: Es ist nur so, wie die Sprache spezifiziert wurde. Traditionell stellt JS sicher, dass Sie immer ein Objekt als haben this, aber im strengen Modus wird dieser Schritt übersprungen, sodass Sie die primitive Zeichenfolge oder was auch immer vorgesehen ist this.
6
Es ist Zeit, "use strict";überall Jungs zu platzieren! Goooold
Jonathan

Antworten:

155

Im strengen Modus muss der thisKontext kein Objekt sein. Wenn Sie eine Funktion für ein Nichtobjekt aufrufen, thisist dies nur dieses Nichtobjekt.

Im nicht strengen Modus wird der thisKontext dagegen immer zuerst in ein Objekt eingeschlossen, wenn es noch kein Objekt ist. Beispielsweise wird (42).toString()zuerst 42ein NumberObjekt umbrochen und dann Number.prototype.toStringmit dem NumberObjekt als thisKontext aufgerufen. Im strikten Modus der thisist Kontext unberührt und nur Anrufe links Number.prototype.toStringmit 42als thisKontext.

(function() {
  console.log(typeof this);
}).call(42); // 'object'

(function() {
  'use strict';
  console.log(typeof this);
}).call(42); // 'number'

In Ihrem Fall verbringt die Version im nicht strengen Modus viel Zeit damit, primitive strings in StringObjekt-Wrapper und zurück zu verpacken und zu entpacken . Die Strict-Mode-Version hingegen arbeitet direkt mit dem Grundelement string, wodurch die Leistung verbessert wird.

Mattias Buelens
quelle
1
Und das Entfernen von withhilft auch ein bisschen für jede variable Suche iirc.
zzzzBov
2
@zzzzBov falsch. Das Entfernen von withhilft immens, da der Browser feststellen kann, welcher Variablenausdruck sich auf welche Variable bezieht.
John Dvorak
2
Scheint mir nicht intuitiv zu sein, dass Nicht-Objekt this"strenger" ist als Immer-Objekt this.
IllidanS4 will Monica
2
@ IllidanS4: Hier geht es hauptsächlich um Fälle , in denen sich das globale Objekt im schlampigen Modus thisbefindet nulloder befindet undefined.
Bergi
6
@ IllidanS4: Betrachten Sie es als "aktuell" this " vs. "Wrapper this", wenn Sie . Objekt-Wrapper sind ein Kludge, der niemals hätte existieren dürfen. Daher ist es sinnvoll, dass der strikte Modus sie nach Möglichkeit stärker vermeidet.
Ry-