定义一个固定尺寸的缓存,当它被填满时,新加入的元素会覆盖第一个(最老的)元素。一般情况我们会选择一个双头队列,可以从任意一头添加或删除数据。或者在运行时,根据缓存有没有满,去改变append函数的指向(方法切换)。但这里借用一下python中的self.__class__可以重新被指向一个新的类的思路(类切换),在javascript中实现一下。
function RingBuffer( size_max ){ this.max = size_max; this.data = []; this.cur = 0; function _full(){ this.append = function( x ){ this.data[this.cur] = x; this.cur = ( this.cur + 1 ) % this.max; } this.tolist = function(){ return this.data.slice(this.cur).concat(this.data.slice(0,this.cur)); } } this.append = function( x ){ this.data[this.cur] = x; this.cur ++ ; if( this.cur == this.max ){ this.cur = 0; delete this.append; delete this.tolist; this.__proto__ = new _full(); } } this.tolist = function(){ return this.data; } }
从未填满状态到填满状态的改变,会使实例的类进行切换,在python中可以通过对self.__class__的设置即可达到目的,但javascript中需要利用原型继承,来达到这一目的,上面的代码适用于firefox和chrome,对于IE,由于没有__proto__属性来引用原型对象(设置RingBuffer.prototype只会修改它自己原型对象的引用,不会修改已实例化对象的原型对象引用),所以当删除this中的方法后,由于找不到方法会报错。
对于IE,如果不能切换类,在javascript中,至少我们还能改变this的上下文
function RingBuffer( size_max ){ this.max = size_max; this.data = []; this.cur = 0; function _full(){ this.append = function( x ){ this.data[this.cur] = x; this.cur = ( this.cur + 1 ) % this.max; } this.tolist = function(){ return this.data.slice(this.cur).concat(this.data.slice(0,this.cur)); } } this.append = function( x ){ this.data[this.cur] = x; this.cur ++ ; if( this.cur == this.max ){ this.cur = 0; _full.call(this); } } this.tolist = function(){ return this.data; } }
到底是运行时进行方法切换,还是进行类切换,python cookbook上建议:方法切换在需要更细行为粒度控制时适合,而在成组的切换所有方法时,类切换可能最佳。
参考资料:python cookbook 6.11