Javascript 构建阵列侦听器
是否有一种方法可以将侦听器附加到另一个进程正在构建的数组,以便在array.length达到某个值时,侦听器执行回调并触发相应的代码Javascript 构建阵列侦听器,javascript,Javascript,是否有一种方法可以将侦听器附加到另一个进程正在构建的数组,以便在array.length达到某个值时,侦听器执行回调并触发相应的代码 fooArray = []; // another code adds objects to array if (fooArray.length = 5) { // callback } else { // continue checking fooArray.length } 您必须使用自己的方法在数组中进行更改 Array.prototype.my
fooArray = [];
// another code adds objects to array
if (fooArray.length = 5) {
// callback
} else {
// continue checking fooArray.length
}
您必须使用自己的方法在数组中进行更改
Array.prototype.myPush = function () {
this.push.apply( this, arguments );
if ( this._binder && this._binder.test.call( this ) ) {
this._binder.callback.call( this );
}
}
Array.prototype.bind = function (tester, callback) {
this._binder = {
test: tester,
callback: callback
};
}
var arr = [4, 6, 9, 20];
arr.bind( function () {
return this.length >= 5;
}, function () {
console.log( "Array has exceeded" );
} );
arr.myPush( 40 );
好的,是和否。没有办法以100%安全的方式完成,因为JavaScript不支持运算符重载,这意味着您不能修改数组索引运算符的行为(
[]
)
但是,很少使用数组索引操作符将数组添加到。也就是说,这是一种非常罕见(但有效)的向数组添加项的方法:
var arr = [];
for( i=0; i<5; i++ ) arr[i] = i;
然后您可以相应地修改push
方法:
arr.push = function() {
var arr = this;
Array.prototype.push.apply( arr, arguments );
arr._listeners.forEach( function(listener) {
listener( { event: 'push', newLength: arr.length } );
});
}
您几乎可以在事件对象中放入任何您想要的内容(如旧计数、添加的元素、时间戳等)
为了使此功能更加强大,您必须将此技术用于修改数组的所有其他Array
方法,例如pop
,shift
,等等。请参见此处的Array
的所有方法:
根据你的需要,你可以考虑其他的技术。例如,如果你做了大量的函数包(就像我们上面的代码>推< /COD>),你应该考虑某种面向方面的编程(AOP)框架。你也可以很容易地写自己的。例如,我们可以重新进行上述工作:
function after( f, after ) {
return function() {
f.apply( this, arguments );
after.apply( this, arguments );
}
}
var arr = [];
// convenience function for broadcasting an event
arr._broadcast = function( o ) {
this._listeners.forEach( function(listener) {
listener( o );
}
}
arr.push = after( arr.push, function() {
this._broadcast( { event: 'push', newLength: arr.length } );
});
这种方法的优点是,可以更容易地扩展数组的其他方法:
arr.pop = after( arr.pop, function() {
this._broadcast( { event: 'pop', newLength: arr.length } );
});
等等
如果您需要能够制作许多这样的“广播”数组,那么正如前面提到的,您可以创建自己的自定义数组类型,扩展array
,但是JavaScript为代码重用提供了比传统OOP更灵活的模式。因此,您不必创建扩展数组的事件数组
,而只需创建数组的函数。prototype
将神奇地使该实例成为事件发射器:
Array.prototype.makeBroadcaster = function() {
this._listeners = this._listeners || [];
this._broadcast = function( o ) {
this._listeners.forEach( function(listener) {
listener( o );
}
this.registerListener = function( listener ) {
this._listeners.push( listener );
}
this.push = after( this.push, function() {
this._broadcast( { event: 'push', newLength: arr.length } );
}
this.pop = after( this.push, function() {
this._broadcast( { event: 'push', newLength: arr.length } );
}
this.shift = after( this.push, function() {
this._broadcast( { event: 'shift', newLength: arr.length } );
}
// etc....
}
现在,每当您有一个数组要广播它发生了什么,您所要做的就是:
var arr = [];
arr.makeBroadcaster();
arr.addListener( function(evt) {
console.log( "%s (new length: %d)", evt.event, evt.newLength );
} );
一些闭幕词:
- 正如我在文章开头提到的,如果代码使用数组索引操作符修改数组,则无法引发该事件。具体来说,可以使用数组索引操作符“增长”数组。换句话说,如果数组包含5个元素,并且执行
arr[9]=“hello”
,那么数组中现在将包含10个元素(其中5-8为未定义的)。没有办法检测到这一点,但以这种方式修改数组是非常罕见的
- 您还可以使用
length
属性修改数组的长度。也就是说,如果您有一个十元素数组,并且您调用arr.length=5
,它将截断该数组,使其只有五个元素。这可能是通过重写length
属性(使用Object.defineProperty
)检测到的,但如果可能的话,这听起来非常危险。同样,以这种方式截断数组在JavaScript中非常少见
- 如果事件确实必须100%准确,即使在上述情况下,那么,您最好能够创建您自己的对象,该对象具有基本的数组功能,如
推送
等。不过,这将非常尴尬,因为您必须实现类似于get(index)
的功能,而不是使用更方便的数组索引操作符
下面是一个JSFIDLE演示了整个过程:
JavaScript不是很整洁吗?错误:如果(fooArray.length==5)传递了回调函数吗?然后使用它:if(callback!=undefined&&typeof callback=='function')callback();不,没有。数组不会引发事件。有许多数据绑定框架以及小型发布/订阅库…可能会研究这些
Array.prototype.makeBroadcaster = function() {
this._listeners = this._listeners || [];
this._broadcast = function( o ) {
this._listeners.forEach( function(listener) {
listener( o );
}
this.registerListener = function( listener ) {
this._listeners.push( listener );
}
this.push = after( this.push, function() {
this._broadcast( { event: 'push', newLength: arr.length } );
}
this.pop = after( this.push, function() {
this._broadcast( { event: 'push', newLength: arr.length } );
}
this.shift = after( this.push, function() {
this._broadcast( { event: 'shift', newLength: arr.length } );
}
// etc....
}
var arr = [];
arr.makeBroadcaster();
arr.addListener( function(evt) {
console.log( "%s (new length: %d)", evt.event, evt.newLength );
} );