有没有办法将侦听器附加到由另一个进程构建的数组,以便当array.length达到某个值时,侦听器执行回调并触发相应的代码?
fooArray = [];
// another code adds objects to array
if (fooArray.length = 5) {
// callback
} else {
// continue checking fooArray.length
}
答案 0 :(得分:3)
你必须使用自己的方法来改变数组
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 );
答案 1 :(得分:3)
嗯,是的,不是。没有办法以100%安全的方式执行,因为JavaScript不支持运算符重载,这意味着您无法修改数组索引运算符([]
)的行为。
但是,使用数组索引运算符添加的数组很少见。也就是说,这是一种非常罕见(但有效)的方法,可以将项添加到数组中:
var arr = [];
for( i=0; i<5; i++ ) arr[i] = i;
结果将是一个包含五个元素的数组。但更常见的是,您会看到:
var arr = [];
for( i=0; i<5; i++ ) arr.push( i );
现在我们可以合作了。因此,现在的解决方案是将push
函数的原始功能与包含引发事件的其他功能结合起来。
有三种基本方法可以做到这一点。第一个是修改Array.prototype.push
。我会引导你清除这种方法:导致极难追踪的缺陷的可能性很高。第二种是创建自己的数组类型,扩展JavaScript的内置Array
类型。如果你要创建许多需要监听的数组,这将是最好的方法。最后一种方法只是修改单个数组,这是最少的工作,以及我将在这里描述的方法。
你可以通过任何这些方法获得所需的复杂功能,但我只会提供一个非常小的基础,允许你附加任意的侦听器,并且可以扩展为其他功能(删除侦听器,引发事件)不同的数组修改方法等。)。
首先,您需要一个数组和一个用于保存侦听器的属性:
var arr = [];
arr._listeners = [];
然后您可以相应地修改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
的方法:
根据您的需求,您可以考虑其他技术。例如,如果你做了很多函数包装(就像我们上面用push
所做的那样),你应该考虑某种面向方面编程(AOP)框架,如meld。你也可以很容易地写自己的。例如,我们可以这样重复上述工作:
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 } );
});
这种方法的优点是可以更容易地扩展Array
的其他方法:
arr.pop = after( arr.pop, function() {
this._broadcast( { event: 'pop', newLength: arr.length } );
});
等等。
如果你需要能够创建许多这样的“广播”数组,你可以像前面提到的那样创建自己的自定义数组类型Array
,但JavaScript提供了更多灵活的代码模式比传统的OOP重复使用。因此,您可以创建一个EventArray
函数,而不是创建扩展Array
的{{1}},这会奇怪地使该实例成为事件发射器:
Array.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....
}
一些结束语:
正如我在帖子开头所提到的,如果您的代码使用数组索引运算符修改数组,则无法在其上引发事件。具体而言,可以使用数组索引运算符“增长”数组。换句话说,如果数组包含5个元素,并且执行var arr = [];
arr.makeBroadcaster();
arr.addListener( function(evt) {
console.log( "%s (new length: %d)", evt.event, evt.newLength );
} );
,则数组中将包含10个元素(5-8为arr[9] = 'hello'
)。没有办法检测到这一点,但是以这种方式修改数组的情况非常罕见。
您还可以使用undefined
属性修改数组的长度。也就是说,如果你有一个十元素数组,并且你调用length
,它将截断数组只有五个元素。可能通过覆盖arr.length = 5
属性(使用length
)来检测到这一点,但如果可能的话,这听起来真的很危险。再次,以这种方式截断数组在JavaScript中非常罕见。
如果事件真的绝对必须100%准确,即使在上面的情况下,你最好的选择是能够创建自己的对象,它具有基本的数组函数,如Object.defineProperty
和喜欢。但是,这将非常尴尬,因为你必须实现push
之类的东西,而不是使用更方便的数组索引操作符。
这是一个展示整个行动的jsfiddle:http://jsfiddle.net/g68jC/
JavaScript不是很整洁吗?