Роботландский Университет © А.А.Дуванов |
Подсчитать сумму элементов массива set можно так (нумерация элементов массива в JavaScript начинается с нуля; set.length свойство массива его длина):
var sum = 0; for(var i=0; i < set.length; i++) sum += set[i];
А можно и так:
var sum = 0; for(var i=set.length; --i>=0; ) sum += set[i];
Перепишем этот вариант суммирования на русском языке:
var s = 0; var i=set.length; ПОВТОРЯТЬ { уменьшить i на 1. проверить i: если i>=0 то s += set[i]; иначе цикл закончить }
Второй способ предпочтительнее.
Сравнение с нулем обычно более эффективно, чем сравнение с другим числом, тем более, сравнение с переменной, которая является собственностью объекта set (до нее еще нужно добраться).
Иными словами --i>=0 работает быстрее, чем i<set.length.
Что касается i=set.length во втором варианте, то это присваивание не крутится в цикле, а работает ровно один раз до входа в него.
Общее правило: в цикле со счетчиком значение счетчика должно по возможности уменьшаться.
Циклы это как раз то место, где имеет смысл оптимизировать программу. Понятно почему: ведь выполнение тела цикла повторяется многократно, и малое улучшение помножается на большое число оборотов. Если цикл выполняется 1000 раз, то такая оптимизация дает тысячекратный выигрыш.
Заметим, что такой вариант:
var sum = 0; for(var i=set.length; (i--)>=0; ) sum += set[i];
является ошибочным, ведь в нем уменьшение i на единицу происходит после проверки условия, а не до, как в правильном варианте.
Можно написать так:
for(var i=100; i; i--) ...
или так:
var i; for(i=100; i; i--) ...
Для браузера эти записи эквивалентны. Вспомним, что в конструкции цикла:
for(начало; условие; приращение) команда;
команда начало выполняется один раз перед первым оборотом цикла. Поэтому ясно, что переменная i не определяется 100 раз описателем var.
Рекомендации такие:
А что происходит, когда описание переменной помещается внутрь цикла while?
Если написать в С++ так:
while(...) { int digit = ... ... }
то переменная digit будет видна только внутри цикла и не
доступна вне его. Дело здесь не в цикле, а в блоке
Такая инкапсуляция переменных имеет смысл, как и инкапсуляции в программировании вообще. Программисты всегда стараются сделать область видимости переменной как можно более узкой. Это обычная практика оборонительного программирования.
Если переменная, подобная digit, используется как рабочая внутри цикла и не имеет смысла вне его, то разумнее объявить ее локальной внутри этого цикла, чем объявлять ее в начале функции с комментарием рабочая переменная цикла такого-то.
Однако, к сожалению, здесь C++ расходится с JavaScript. Для JavaScript запись:
while(...) { var digit = ... ... }
эквивалентна такой:
var digit; ... while(...) { digit =.... }
С этим печальным фактом приходится считаться. Но в обоих случаях переменная digit создается один раз. Ведь описание это не команда, а декларация. Браузер просматривает скрипт и выделяет под все переменные память, а только потом начинает выполнять команды.
Конструкция, в которой совмещены декларация и команда:
var digit = 10;
выполняется браузером так: сначала под переменную отводится память, а затем в нее помещается число 10.
Если браузер не может выполнить инициализацию переменной при ее создании:
function fun(t) { var x = t+1; ... }
то он отделяет создание переменной от ее вычисления. Переменная
создается один раз при первом просмотре функции (подготовка к работе),
затем работают команды функции и среди них команда
![]() |