DOM 操作
我同意@samccone 的观点,如果GetList() 和GetListItem() 每次都在执行 DOM 操作,您应该尽量保存对这些调用检索到的元素的引用,并减少 DOM 操作。
然后我可以操纵该变量,并希望它不会通过调用 offsetLeft 与“真实”值不同步。
您只需将 DOM 元素的引用存储在变量中。因为它是一个参考,它是真正的价值。它是同一个确切的对象。例如:
var li = ul.getElementsByTagName( "li" )[ index ];
存储对 DOM 对象的引用。您可以随时从该对象读取offsetLeft,而无需执行另一个DOM 操作(如getElementsByTagName)来检索该对象。
另一方面,以下内容只会存储值,不会保持同步:
var offsetLeft = ul.getElementsByTagName( "li" )[ index ].offsetLeft;
左偏移
如果offsetLeft 真的是一个瓶颈,你是否可以重新编写它以减少阅读量?在这种情况下,每次轮换第一项时,您是否可以为新的第一项读取一次offsetLeft,然后在每次调用MoveLeft() 时将该值递减,直到达到0(或其他)?例如
function MoveLeft( px ) {
current_offset -= px;
如果你想更积极地避免offsetLeft,也许你可以做一些事情,你读取每个列表项的宽度一次,并读取第一个项目的offsetLeft,然后使用这些值来确定何时轮换,无需再次调用offsetLeft。
全局变量
我想我明白了...所以 elms["foo"] 必须是一个全局变量?
我认为我真的只需要使用全局变量而不是每 10 毫秒调用一次 offsetLeft。
你不需要使用全局变量,事实上你应该避免它——这是糟糕的设计。在不使用全局变量的情况下,您至少可以采用几种好方法:
-
您可以将整个程序包装在一个闭包中:
( 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调用函数不会干扰函数对封闭变量的访问。这是一个简单的演示 sn-p:
( 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 属性,而无需重复执行getElementsByTagName() 等DOM 操作来获取列表对象。
#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