Bu örnekte neden "sıkı kullanmak" performansı 10 kat artırır?


128

String.prototype performansını genişletme sorusunun ardından gerçekten meraklandım , çünkü "use strict"bir String.prototypeyönteme sadece 10 kat daha iyi performans ekledim . Açıklama ile Bergi kısadır ve bana açıklamaz. Neredeyse aynı iki yöntem arasında neden yalnızca "use strict"en üstte farklılık gösteren bu kadar çarpıcı bir fark var ? Daha detaylı olarak ve bunun arkasındaki teori ile açıklayabilir misiniz?

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');

Sonuç:

proto: 101 ms
proto-strict: 7.5 ms

1
Bir test this[i] === charyapıp aynı farkı alıp almadığınızı görebilir misiniz?
Niet the Dark Absol

1
this[i] === charBir DOM ortamında test ettim ve sonuç aynı
Cristian Traìna

2
bergi'nin açıklaması, countişlevi çağırdığınızda, thisparametrenin bir dizge değişmezi yerine bir dizge nesnesine dönüştürülmesi gerektiğini, ancak katı modda doğru şekilde çalışması için gerekli olmadığını söyler . Neden bu durum benim dışımda, cevapla çok ilgileniyorum.
Nick Larsen

3
@NickLarsen: Dil nasıl belirlendi. Geleneksel olarak JS, her zaman olduğu gibi bir nesneye sahip olduğunuzdan emin olur this, ancak katı modda bu adımı atlar, böylece ilkel dizeyi veya sağlanan her şeyi elde edersiniz this.

6
Her yere koyma zamanı "use strict";çocuklar! Goooold
Jonathan

Yanıtlar:


155

Katı modda, thisbağlam bir nesne olmaya zorlanmaz. Nesne olmayan bir işlevi çağırırsanız, thiso nesne olmayan olacaktır.

Buna karşılık, katı olmayan modda, thisbağlam zaten bir nesne değilse, her zaman önce bir nesneye sarılır. Örneğin, (42).toString()ilk sargıları 42bir de Numberdaha sonra nesne ve aramaları Number.prototype.toStringile Numbernesneye thisbağlamında. Katı modda, thisbağlam bakir ve sadece telefon bırakılır Number.prototype.toStringile 42olarak thisbağlamda.

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

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

Sizin durumunuzda, katı olmayan mod sürümü, ilkel stringe- postaları Stringnesne sarmalayıcılara ve geri sarmaya çok fazla zaman harcar . Öte yandan katı mod sürümü, doğrudan ilkel üzerinde çalışır ve stringbu da performansı artırır.


1
Ve withiirc'nin kaldırılması da her değişken arama için biraz yardımcı olur.
zzzzBov

2
@zzzzBov yanlış. Seçeneğinin kaldırılması , tarayıcının hangi değişken ifadesinin hangi değişkeni ifade ettiğine karar vermesine izin verdiği için büyük ölçüdewith yardımcı olur .
John Dvorak

2
Nesne-olmayanın thisher zaman-nesneden "daha katı" olması bana mantıksız geliyor this.
IllidanS4 Monica'yı

2
@ IllidanS4: Bu durumda ilgili çoğunlukla thisbir nullya da undefinedözensiz modunda küresel nesne olacaktır.
Bergi

6
@ IllidanS4: İsterseniz bunu "gerçek this" ve "sarmalayıcı this" olarak düşünün . Nesne sarmalayıcılar, asla var olmaması gereken bir kludge'dır, bu nedenle katı modun mümkün olduğunda bunlardan daha fazla kaçınacağı mantıklıdır.
Ry-
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.