В ECMA-262 5th edition есть такая замечательная вообщем-то штука как strict mode. Тут вот всплыл достаточно внятный пример, почему strict mode --- это в некотором роде счастье.
Допустим пишем мы на JavaScript и решили примешать к встроенному типу String свой метод. Сказано...
String.prototype.foo = function () {
// do something nasty with this
};
сделано! Однако, простой замер в стиле:
var str = "";
for (var i = 1; i < 1e7; i++) str.foo();
показывает, что вызов foo какой-то ну слишком дорогой, причем на V8 раз 100-200 дороже чем:
function foo(this_) { /* do something nasty with this_ */ }
for (var i = 1; i < 1e7; i++) foo(str);
Хмм, скажет погруженный в нормальные языки программирования читатель и полезет в ECMA-262 5th edition за объяснениями. Там он с удивлением обнаружит , что вызывая метод на примитивной строчке, мы на самом деле каждый раз неявно создаем объект, который потом используется в качестве this:
str.foo(); // ⇒ new String(str).foo()
в V8 причем этот случай* вообще не обрабатывается в сгенерированном коде, поэтому каждый вызов str.foo() проваливается в среду исполнения: вот и получается аллокация + сборки мусора + вызов через среду исполнения + IC из-за этого лихорадит = 100x-200x замедление. * - встроенные функции на прототипе String (типа indexOf) все-таки оптимизированы и не требуют оборачивания примитивной строчки в объект, потому их вызов быстр
Печаль. Вот тебе бабушка и функция на прототипе String. Тут можно порассуждать о том, что для таких случаев неплохо бы особое состояние у IC завести и выполнять заворачивание примитивной строчки в объект в коде, без входа в среду исполнения, а еще неплохобы переиспользовать врапперы (делая copy-on-write, когда их кто-нибудь меняет), но это все детали...
Потому что тут открывается дверь и на белом коне въезжает strict mode! Если внимательно читать ECMA-262 5th раздел 10.4.3 Entering Function Сode (я честно признаюсь, когда читал первый раз проглядел этот момент *facepalm* и позор на мою седую голову), то можно заметить, что:
1. If the function code is strict code, set the ThisBinding to thisArg.
2. Else if thisArg is null or undefined, set the ThisBinding to the global object.
3. Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
4. Else set the ThisBinding to thisArg.
Если функция строгая, то заворачивать ничего не надо!
Отсюда правило: объявляешь функцию на прототипе String/Number/Boolean сделай её строгой:
String.prototype.foo = function () {
"use strict";
// do something nasty with this
};
и тогда наверняка (ну или почти наверняка, если твой JavaScript движок поддерживает strict mode) вызов этой функции станет быстрее!
По мотивам
треда в nodejs