операций DOM
Я согласен с @samccone в том, что если GetList()
и GetListItem()
выполняют операции DOM каждый раз, вам следует постараться максимально сохранить ссылки на элементы, полученные этими вызовами, и сократить количество операций DOM.
тогда я могу просто манипулировать этой переменной, и, надеюсь, она не будет синхронизирована с "реальным" значением, вызвав offsetLeft.
Вы просто сохраните ссылку на элемент DOM в переменной. Поскольку это ссылка, является реальным значением. Это точно такой же объект. E.g.:
var li = ul.getElementsByTagName( "li" )[ index ];
Хранит ссылку на объект DOM. Вы можете прочитать offsetLeft
из этого объекта в любое время, не выполняя другую операцию DOM (например, getElementsByTagName
) для извлечения объекта.
С другой стороны, следующее просто сохранит значение и не будет синхронизироваться:
var offsetLeft = ul.getElementsByTagName( "li" )[ index ].offsetLeft;
offsetLeft
Если offsetLeft
действительно является узким местом, возможно, вы могли бы переработать это, чтобы просто прочитать его намного меньше? В этом случае, каждый раз, когда вы поворачиваете первый элемент, вы можете прочитать offsetLeft
один раз для нового первого элемента, а затем просто уменьшать это значение в каждом вызове до MoveLeft()
, пока оно не достигнет 0
(или что-то еще)? Э.Г.
function MoveLeft( px ) {
current_offset -= px;
Если вы хотите стать еще более агрессивным в отношении отказа от offsetLeft
, возможно, вы могли бы сделать что-то, где вы прочитаете ширину каждого элемента списка один раз и offsetLeft
первого элемента один раз, а затем просто используйте эти значения для определить, когда вращаться, никогда не вызывая offsetLeft
снова.
Глобальные переменные
Думаю, я понял ... поэтому elms ["foo"] должен быть глобальной переменной?
Я думаю, что на самом деле мне просто нужно использовать глобальные переменные вместо вызова offsetLeft каждые 10 мс.
Вам не нужно использовать глобальные переменные, и на самом деле вам следует избегать этого - это плохой дизайн. Есть по крайней мере несколько хороших подходов, которые вы можете использовать, не используя глобальные переменные:
Вы можете заключить всю программу в закрытие:
( function () {
var elements = {};
function NeedsRotating() {
...
}
function example() {
// The follow var declaration will block access
// to the outer `elements`
var elements;
}
// Rest of your code here
} )();
Там elements
относится к анонимной функции, которая его содержит. Это не глобальная переменная и не будет видна вне анонимной функции. Он будет виден любому коду, включая функции (например, NeedsRotating()
в данном случае), внутри анонимной функции, если вы не объявляете переменную с тем же именем во внутренних функциях.
Вы можете инкапсулировать все в объекте:
( function () {
var ticker = {};
ticker.elements = {};
// Assign a method to a property of `ticker`
ticker.NeedsRotating = function () {
// All methods called on `ticker` can access its
// props (e.g. `elements`) via `this`
var ul = this.elements.list;
var li = this.elements.list_item;
// Example of calling another method on `ticker`
this.do_something();
} ;
// Rest of your code here
// Something like this maybe
ticker.start();
} )();
Здесь я снова завернул все в анонимную функцию, так что даже ticker
не является глобальной переменной.
Ответ на комментарий
Прежде всего, относительно setTimeout
, вам лучше сделать это:
t = setTimeout( TickerLoop, i );
вместо:
t = setTimeout("TickerLoop();", i);
В JS функции являются объектами первого класса, поэтому вы можете передать фактический объект функции в качестве аргумента setTimeout
вместо передачи строки, что аналогично использованию eval
.
Вы можете рассмотреть setInterval
вместо setTimeout
.
Потому что, конечно, любой код, выполняемый в setTimeout, будет выходить за рамки закрытия?
На самом деле это не так. Закрытие формируется, когда функция определена. Таким образом, вызов функции через setTimeout
не мешает доступу функции к закрытым переменным. Вот простой демонстрационный фрагмент:
( function () {
var offset = 100;
var whatever = function () {
console.log( offset );
};
setTimeout( whatever, 10 );
} )();
Однако
setTimeout
будет мешать связыванию this
в ваших методах, что будет проблемой, если вы инкапсулируете все в объекте. Следующее не будет работать:
( function () {
var ticker = {};
ticker.offset = 100;
ticker.whatever = function () {
console.log( this.offset );
};
setTimeout( ticker.whatever, 10 );
} )();
Внутри ticker.whatever
, this
не будет ссылаться на ticker
. Однако здесь вы можете использовать анонимную функцию, чтобы сформировать замыкание для решения проблемы:
setTimeout( function () { ticker.whatever(); }, 10 );
Если я сохраню его в переменной класса, т.е. var ticker.SecondLiOffsetLeft = GetListItem(ul, 1).offsetLeft
, тогда мне придется только снова вызывать offsetLeft
, когда я поворачиваю список.
Я думаю, что это лучшая альтернатива глобальной переменной?
Ключевые вещи:
Доступ к offsetLeft
один раз при каждом повороте списка.
Если вы храните элементы списка в переменной, вы можете получить доступ к их свойству offsetLeft
без необходимости многократного выполнения операций DOM, таких как getElementsByTagName()
, для получения объектов списка.
Переменная в # 2 может быть либо свойством объекта, если вы заключаете все в объект, либо просто переменной, которая доступна вашим функциям через область их закрытия. Я бы, наверное, завернул это в объект.
Я обновил раздел «Операции DOM», чтобы уточнить, что если вы сохраните ссылку на объект DOM, это будет точно такой же объект. Вы не хотите хранить offsetLeft
напрямую, так как это просто сохранит значение и не будет синхронизировано.
Однако, если вы решите сохранить их (например, свойство объекта или переменную), вам, вероятно, следует извлечь все объекты li
один раз и сохранить их в массивоподобной структуре. Э.Г.
this.li = ul.getElementsByTagName( "li" );
Каждый раз, когда вы вращаете, как-то указываете текущий элемент, например ::
this.current_item = ###;
// or
this.li.current = this.li[ ### ];
// Then
this.li[ this.current_item ].offsetLeft
// or
this.li.current.offsetLeft
Или, если хотите, вы можете сохранить объекты li
в массиве и делать это для каждого поворота:
this.li.push( this.li.shift() );
// then
this.li[0].offsetLeft