Почему «использование строгого» повышает производительность в 10 раз в этом примере?

После вопросаРасширение производительности String.prototype Я действительно заинтригован, потому что просто добавив"use strict" кString.prototype Метод улучшил производительность в 10 раз.объяснение отБерги является коротким и не объясняет это мне. Почему между двумя почти идентичными методами существует такое различие, которое отличается только"use strict" на вершине? Можете ли вы объяснить более подробно и с теорией, стоящей за этим?

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

Результат:

proto: 101 ms
proto-strict: 7.5 ms
 Jared Smith17 июл. 2016 г., 01:59
 Nick Larsen16 июл. 2016 г., 15:28
объяснение Берги говорит, что когда вы называетеcount функция,this Параметр должен быть приведен к строковому объекту, а не к строковому литералу, тогда как в строгом режиме он не должен работать правильно. Почему это так, мне не интересно, мне очень интересен ответ.
 Niet the Dark Absol16 июл. 2016 г., 15:12
Можете ли вы сделать тест сthis[i] === char и посмотрим, получишь ли ты такую ​​же разницу?
 Cristian Traìna16 июл. 2016 г., 15:28
Я проверял сthis[i] === char в среде DOM, и результат тот же
 user110692516 июл. 2016 г., 15:33
@NickLarsen: Это просто, как язык был задан. Традиционно JS следит за тем, чтобы у вас всегда был объект какthis, но в строгом режиме он пропускает этот шаг, так что вы получитепримитивный строка, или что-то дляthis.
 Jonathan16 июл. 2016 г., 15:36
Пришло время ставить"use strict"; везде мальчики! Goooold

Ответы на вопрос(1)

Решение Вопроса

В строгом режимеthis контекст не обязательно должен быть объектом. Если вы вызываете функцию не-объекта,this будет просто не-объект.

Напротив, в нестрогом режимеthis контекст всегда сначала обернут в объект, если это еще не объект. Например,(42).toString() первые обертывания42 вNumber объект, а затем вызываетNumber.prototype.toString сNumber объект какthis контекст. В строгом режимеthis контекст остается нетронутым и просто вызываетNumber.prototype.toString с42 какthis контекст.

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

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

В вашем случае версия в нестрогом режиме тратит много времени на развертывание и развертывание примитива.stringвString обертки объектов и обратно. Версия строгого режима, с другой стороны, напрямую работает на примитивеstring, что улучшает производительность.

 zzzzBov16 июл. 2016 г., 15:41
И удалениеwith также помогает немного для поиска каждой переменной iirc.
 Black26 июл. 2016 г., 14:13
Так что мы должны всегда использоватьstrict mode если мы будем работать сthis?
 John Dvorak16 июл. 2016 г., 20:21
@zzzzBov неверно. Удалениеwith помогаеточень поскольку это позволяет браузеру рассуждать, какое выражение переменной относится к какой переменной.
 Neil17 июл. 2016 г., 11:18
Я проверял сString объекты и время были одинаковыми для каждой функции (после учета экспериментальной ошибки). Они также были в шесть раз быстрее, чем нестрогая версия, и в 17 раз медленнее, чем строгая версия на необработанных строках в моей системе. Я также добавилvar self = String(this); и т.д. к нестрогой версии, и это фактически довело скорость до такой же, как строгая версия дляString объекты, но необработанные строки были все еще на 50% медленнее, вероятно, из-заString строительные накладные.
 Black27 июл. 2016 г., 08:12
Есть лиstrict mode всегда повышать производительность?
 Bergi17 июл. 2016 г., 12:57
@ IllidanS4: Это в основном о случаях, когдаthis являетсяnull или жеundefined, который будет глобальным объектом в небрежном режиме.
 Mattias Buelens26 июл. 2016 г., 19:22
@EdwardBlack Строгий режим исправляет некоторые ошибки в «старой» семантике JavaScript, помогает предотвратить ошибки, превращая скрытые ошибки в реальные ошибки, и позволяет браузерам лучше оптимизировать код. Вам следуетвсегда используйте строгий режим, если вы пишете новый код JavaScript сегодня. Однако включение строгого режима может нарушить унаследованный код, поэтому будьте осторожны при переходе старого кода на современный JavaScript.
 Oriol16 июл. 2016 г., 21:33
Теоретически,this.length а такжеthis[i] Также следует создать строковый экзотический объект (строковые примитивы не имеют свойств), но, вероятно, браузеры этого не делают.
 IllidanS417 июл. 2016 г., 12:33
Мне кажется не понятным, что не объектthis "строже", чем всегда-объектthis.
 Ry-18 июл. 2016 г., 07:37
@ IllidanS4: Думайте об этом как "фактическийthis"против" оберткаthis«если хотите. Обертки объектов - это кладжа, которой никогда не должно было быть, поэтому имеет смысл, что строгий режим позволит избежать их больше, когда это возможно.

Ваш ответ на вопрос