I wanted to extend the prototype of the String
object with some useful methods. It worked, but the performance was surprisingly low. For some reason, passing a string in a function is x10 times faster than overriding the method String.prototype
, which does the same. To check that this is really happening, I created a very simple example, the count()
function and the corresponding method.
(I experimented and created three different versions of the method.)
function count(str, char) { var n = 0; for (var i = 0; i < str.length; i++) if (str[i] == char) n++; return n; } 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_reuse = function (char) { return count(this, char) } String.prototype.count_var = function (char) { var str = this; var n = 0; for (var i = 0; i < str.length; i++) if (str[i] == char) n++; return n; } // Here is how I measued speed, using Node.js 6.1.0 var STR ='0110101110010110100111010011101010101111110001010110010101011101101010101010111111000'; var REP = 1e3//6; console.time('func') for (var i = 0; i < REP; i++) count(STR,'1') console.timeEnd('func') console.time('proto') for (var i = 0; i < REP; i++) STR.count('1') console.timeEnd('proto') console.time('proto-reuse') for (var i = 0; i < REP; i++) STR.count_reuse('1') console.timeEnd('proto-reuse') console.time('proto-var') for (var i = 0; i < REP; i++) STR.count_var('1') console.timeEnd('proto-var')
Results:
func: 705 мс proto: 10011 мс proto-reuse: 10366 мс proto-var: 9703 мс
As you can see, the difference is significant.
The example below shows that the performance of method calls is negligible, and that the functions themselves are shorter than methods.
var STR ='0110101110010110100111010011101010101111110001010110010101011101101010101010111111000'; var REP = 1e3//6; function count_dummy(str, char) { return 1234; } String.prototype.count_dummy = function (char) { return 1234; // Just to prove that accessing the method is not the bottle-neck. } console.time('func-dummy') for (var i = 0; i < REP; i++) count_dummy(STR,'1') console.timeEnd('func-dummy') console.time('proto-dummy') for (var i = 0; i < REP; i++) STR.count_dummy('1') console.timeEnd('proto-dummy') console.time('func-dummy') for (var i = 0; i < REP; i++) count_dummy(STR,'1') console.timeEnd('func-dummy')
Results:
func-dummy: 0.165 мс proto-dummy: 0.247 мс func-dummy: 0.045 мс
Despite the huge number of repetitions (of the order of 1e8), the prototyped methods turned out to be x10 times slower than the functions, but this can be ignored for this case.
This can only be associated with a String object, because it does the same thing, regardless of how the methods are called:
var A = { count: 1234 }; function getCount(obj) { return obj.count } A.getCount = function() { return this.count } console.time('func') for (var i = 0; i < 1e9; i++) getCount(A) console.timeEnd('func') console.time('method') for (var i = 0; i < 1e9; i++) A.getCount() console.timeEnd('method')
Results:
func: 1689.942 мс method: 1674.639 мс
The search on Stackoverflow was unsuccessful - aside from the general recommendation “ do not expand String and Array - it litters the namespace ” (which is not a problem specifically for my project), I could not find performance related methods compared to functions. It turns out that I should just forget about the extension of the String class due to the performance drop of the methods being added? Does anyone know more about this?
Translation of the question " Extending String.prototype performance shows that function calls are 10x faster " @exebook .