Прежде всего, для теста, который пытается измерить аргументы против поведения производительности локальных переменных, вы делаете слишком много в каждом случае - вы выделяете закрытие снова и снова, вы выделяете объект из литерала объекта, вы используете for-in. Все эти операции - это путь больше дороже, чем доступ к локальной переменной. Их затраты включают в себя и скрывают любой доступ к переменной стоимости.
Теперь аномалия, которую вы видите, связана с тем, что V8 не имеет быстрого пути для создания замыканий, содержащих литералы: есть FastNewClosureStub
, но он используется только тогда, когда в закрытии нет литералов [1]. Это делает распределение закрытия более дорогостоящим в первом случае по сравнению со вторым - вы видите это отраженное в счете, поскольку распределение закрытия является довольно доминирующей частью вашего теста (он выделяет одно замыкание на op).
Если вы «спрятали» литеральное создание [2] в отдельную функцию, вы увидите аномалию. Примечание: такое скрытие не делает референтный тест более актуальным: все равно не измерение того, что вы хотите измерить.
В целом попытка захвата характеристик производительности переменного доступа в эталоне очень сложна, поскольку они обычно относятся к самым быстрым и наименьшим операциям даже в коде, создаваемом не оптимизирующим (базовым) компилятором. В наиболее распространенном случае, когда никакие переменные не захватываются, а область не содержит with
, eval
или arguments
объект - между аргументами и доступом к локальной переменной не будет различий, скомпилированных в одну загрузку памяти.
[1] https://github.com/v8/v8-git-mirror/blob/9def087efcd844342c35f42628bac4ead49cac81/src/ia32/full-codegen-ia32.cc#L1213-L1218
[2] http://jsperf.com/variable-vs-variable-passed-as-an-argument-to-a-self-in/3
Просто для записи, равные результаты в IE 11. –