Perché "usare rigoroso" migliora le prestazioni 10 volte in questo esempio?


128

A seguito della domanda sull'estensione delle prestazioni di String.prototype, sono davvero incuriosito, perché l'aggiunta "use strict"a un String.prototypemetodo ha migliorato le prestazioni 10 volte. La spiegazione di Bergi è breve e non me la spiega. Perché c'è una differenza così drammatica tra due metodi quasi identici, che differiscono solo nella "use strict"parte superiore? Puoi spiegare in modo più dettagliato e con la teoria alla base di questo?

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

Risultato:

proto: 101 ms
proto-strict: 7.5 ms

1
Puoi fare un test con this[i] === chare vedere se ottieni la stessa differenza?
Niet the Dark Absol,

1
Ho provato con this[i] === charun ambiente DOM e il risultato è lo stesso
Cristian Traìna,

2
La spiegazione di Bergi dice che quando si chiama la countfunzione, il thisparametro deve essere lanciato su un oggetto stringa anziché su un valore letterale stringa mentre in modalità rigorosa non è necessario per funzionare correttamente. Perché questo è il caso oltre me, sono molto interessato alla risposta.
Nick Larsen,

3
@NickLarsen: è proprio come è stata specificata la lingua. Tradizionalmente JS si assicurerebbe che tu abbia sempre avuto un oggetto come this, ma in modalità rigorosa salta quel passaggio, in modo da ottenere la stringa primitiva o qualsiasi cosa fosse prevista this.

6
È tempo di mettere "use strict";ovunque ragazzi! Goooold
Jonathan,

Risposte:


155

In modalità rigorosa, il thiscontesto non è costretto a essere un oggetto. Se chiamate una funzione su un non oggetto,this sarà solo quel non oggetto.

Al contrario, in modalità non rigorosa, il thiscontesto è sempre prima racchiuso in un oggetto se non è già un oggetto. Ad esempio, (42).toString()prima avvolge 42un Numberoggetto e quindi chiama Number.prototype.toStringl' Numberoggetto come thiscontesto. In modalità rigorosa, il thiscontesto è lasciato chiamate intatto e solo Number.prototype.toStringcon 42come thiscontesto.

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

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

Nel tuo caso, la versione in modalità non rigorosa impiega molto tempo a avvolgere e scartare le primitive stringin Stringinvolucri di oggetti e ritorno. D'altra parte, la versione in modalità rigorosa funziona direttamente sulla primitiva string, migliorando le prestazioni.


1
E la rimozione di withaiuta anche un po 'per ogni ricerca iirc variabile.
zzzzBov,

2
@zzzzBov errato. La rimozione di withaiuta immensamente in quanto consente al browser di ragionare quale espressione di variabile si riferisce a quale variabile.
John Dvorak,

2
Non mi sembra intuitivo che il non-oggetto thissia "più rigoroso" del sempre-oggetto this.
IllidanS4 vuole Monica indietro il

2
@ IllidanS4: si tratta principalmente di casi in cui si thistrova nullo undefined, che sarebbe l'oggetto globale in modalità sciatta.
Bergi,

6
@ IllidanS4: pensalo come "reale this" vs. "wrapper this" se vuoi. I wrapper di oggetti sono un kludge che non avrebbe mai dovuto esistere, quindi ha senso che la modalità rigorosa li eviterebbe di più quando possibile.
Ry-
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.