Чому "використовувати строгий" в цьому прикладі покращує продуктивність на 10 разів?


128

Після запитання Розширення продуктивності 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

1
Чи можете ви зробити тест this[i] === charі побачити, чи отримаєте ви однакову різницю?
Niet the Dark Absol

1
Я тестував this[i] === charу середовищі DOM, і результат той самий
Крістіан Трайна

2
Пояснення bergi говорить про те, що при виклику countфункції thisпараметр повинен бути переданий об'єкту рядка замість рядкового літералу, тоді як у строгому режимі це не потрібно для правильної роботи. Чому це справа не в мене, мені дуже цікава відповідь.
Нік Ларсен

3
@NickLarsen: Просто мова промовлялась. Традиційно JS переконається, що у вас завжди був об'єкт як this, але в суворому режимі він пропускає цей крок, тож ви отримуєте примітивний рядок або все, що було передбачено this.

6
Настав час "use strict";скрізь поставити хлопців! Goooold
Джонатан

Відповіді:


155

У суворому режимі 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, що покращує продуктивність.


1
І видалення withтакож трохи допомагає для кожної iirc пошуку змінної.
zzzzBov

2
@zzzzBov неправильно. Видалення withдопомагає надзвичайно, оскільки дозволяє браузеру міркувати, яке вираження змінної відноситься до якої змінної.
Джон Дворак

2
Мені здається неінтуїтивним, що необ'єкт this"суворіший", ніж завжди об'єкт this.
IllidanS4 хоче, щоб Моніка повернулася

2
@ IllidanS4: Це здебільшого про випадки, коли thisє nullабо undefined, який був би глобальним об’єктом у неохайному режимі.
Бергі

6
@ IllidanS4: якщо ви хочете, подумайте про це як "фактичне this" та "обгорткове this". Обгортки об'єктів - це хижість, яка ніколи не мала існувати, тому має сенс, щоб суворий режим уникав їх більше, коли це можливо.
Ry-
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.