Javascript:将事件侦听器附加到Array的Push()事件

时间:2022-06-04 00:00:02

Is there a way to know when a user has pushed (via push()) an item onto an array?

有没有办法知道用户何时(通过push())将项目推送到数组?

Basically I have an asynchronous script that allows the user to push commands onto an array. Once my script loads, it execute the commands. The problems is, the user may push additional commands onto the array after my script has already run and I need to be notified when this happens. Keep in mind this is just a regular array that the user creates themselves. Google Analytics does something similar to this.

基本上我有一个异步脚本,允许用户将命令推送到一个数组。加载脚本后,它会执行命令。问题是,用户可能会在我的脚本运行后将其他命令推送到阵列上,我需要在发生这种情况时收到通知。请记住,这只是用户自己创建的常规数组。 Google Analytics(分析)会执行类似的操作。

I also found this which is where I think Google does it, but I don't quite understand the code: Aa = function (k) { return Object.prototype[ha].call(Object(k)) == "[object Array]"

我也发现这是我认为Google所做的,但我不太了解代码:Aa = function(k){return Object.prototype [ha] .call(Object(k))==“[object阵列]”

I also found a great example which seems to cover the bases, but I can't get my added push method to work correctly: http://jsbin.com/ixovi4/4/edit

我还找到了一个很好的例子,它似乎涵盖了基础,但我无法让我添加的推送方法正常工作:http://jsbin.com/ixovi4/4/edit

11 个解决方案

#1


23  

You could use an 'eventify' function that overrides push in the passed array.

你可以使用'eventify'函数来覆盖传入数组中的push。

var eventify = function(arr, callback) {
    arr.push = function(e) {
        Array.prototype.push.call(arr, e);
        callback(arr);
    };
};

In the following example, 3 alerts should be raised as that is what the event handler (callback) does after eventify has been called.

在下面的示例中,应该引发3个警报,因为这是在调用eventify之后事件处理程序(回调)所执行的操作。

var testArr = [1, 2];

testArr.push(3);

eventify(testArr, function(updatedArr) {
  alert(updatedArr.length);
});

testArr.push(4);
testArr.push(5);
testArr.push(6);

#2


22  

The only sensible way to do this is to write a class that wraps around an array:

唯一明智的做法是编写一个包装数组的类:

function EventedArray(handler) {
   this.stack = [];
   this.mutationHandler = handler || function() {};
   this.setHandler = function(f) {
      this.mutationHandler = f;
   };
   this.callHandler = function() { 
      if(typeof this.mutationHandler === 'function') {
         this.mutationHandler();
      }
   };
   this.push = function(obj) {
      this.stack.push(obj);
      this.callHandler();
   };
   this.pop = function() {
      this.callHandler();
      return this.stack.pop();
   };
   this.getArray = function() {
      return this.stack;
   }
}

var handler = function() {
   console.log('something changed');
};

var arr = new EventedArray(handler);

//or 

var arr = new EventedArray();
arr.setHandler(handler);


arr.push('something interesting'); //logs 'something changed'

#3


13  

try this:

var MyArray = function() { };
MyArray.prototype = [];
MyArray.prototype.push = function() {
    console.log('push now!');
    for(var i = 0; i < arguments.length; i++ ) {
        Array.prototype.push.call(this, arguments[i]);
    }
};

var arr = new MyArray();
arr.push(2,3,'test',1);

you can add functions at after pushing or before pushing

你可以在推或推之前添加功能

#4


3  

Why not just do something like this?

为什么不做这样的事情呢?

Array.prototype.eventPush = function(item, callback) {
  this.push(item);
  callback(this);
}

Then define a handler.

然后定义一个处理程序

handler = function(array) {
    console.log(array.length)
}

Then use the eventPush in the place that you want a specific event to happen passing in the handler like so:

然后在你希望特定事件发生的地方使用eventPush,如下所示:

a = []
a.eventPush(1, handler);
a.eventPush(2, handler);

#5


2  

I'd wrap the original array around a simple observer interface like so.

我将原始数组包装在一个简单的观察者界面周围。

function EventedList(list){
    this.listbase = list;
    this.events = [];
}

EventedList.prototype.on = function(name, callback){
    this.events.push({
        name:name,
        callback:callback
    });
}

//push to listbase and emit added event
EventedList.prototype.push = function(item){
    this.listbase.push(item);
    this._emit("added", item)
}

EventedList.prototype._emit = function(evtName, data){
    this.events.forEach(function(event){
        if(evtName === event.name){
            event.callback.call(null, data, this.listbase);
        }
    }.bind(this));
}

Then i'd instantiate it with a base array

然后我用基数组实例化它

    //returns an object interface that lets you observe the array
    var evtList = new EventedList([]);

    //attach a listener to the added event
    evtList.on('added', function(item, list){
         console.log("added event called: item = "+ item +", baseArray = "+ list);
    })

    evtList.push(1) //added event called: item = 1, baseArray = 1
    evtList.push(2) //added event called: item = 2, baseArray = 1,2
    evtList.push(3) //added event called: item = 3, baseArray = 1,2,3

you can also extend the observer to observe other things like prePush or postPush or whatever events you'd like to emit as you interact with the internal base array.

您还可以扩展观察者以观察其他内容,例如prePush或postPush,或者当您与内部基本阵列交互时要发出的任何事件。

#6


1  

This will add a function called onPush to all arrays, by default it shouldn't do anything so it doesn't interfere with normal functioning arrays.

这将向所有数组添加一个名为onPush的函数,默认情况下它不应该执行任何操作,因此它不会干扰正常运行的数组。

just override onPush on an individual array.

只需覆盖单个数组上的onPush。

Array.prototype.oldPush = Array.prototype.push;
Array.prototype.push = function(obj){
    this.onPush(obj);
    this.oldPush(obj);
};
//Override this method, be default this shouldnt do anything. As an example it will.
Array.prototype.onPush = function(obj){
    alert(obj + 'got pushed');
};

//Example
var someArray = [];

//Overriding
someArray.onPush = function(obj){
    alert('somearray now has a ' + obj + ' in it');
};

//Testing
someArray.push('swag');

This alerts 'somearray now has a swag in it'

这个警告'某些人现在有一个赃物'

#7


1  

Sometimes you need to queue things up before a callback is available. This solves that issue. Push any item(s) to an array. Once you want to start consuming these items, pass the array and a callback to QueuedCallback(). QueuedCallback will overload array.push as your callback and then cycle through any queued up items. Continue to push items to that array and they will be forwarded directly to your callback. The array will remain empty.

有时您需要在回调可用之前排队。这解决了这个问题。将任何项目推送到数组。一旦您想开始使用这些项目,请将数组和回调传递给QueuedCallback()。 QueuedCallback会将array.push重载为您的回调,然后遍历任何排队的项目。继续将项目推送到该阵列,它们将直接转发到您的回调。该数组将保持为空。

Compatible with all browsers and IE 5.5+.

兼容所有浏览器和IE 5.5+。

var QueuedCallback = function(arr, callback) {
  arr.push = callback;
  while (arr.length) callback(arr.shift());
};

Sample usage here.

此处使用示例。

#8


0  

Untested, but I am assuming something like this could work:

未经测试,但我假设这样的东西可以工作:

Array.prototype.push = function(e) {
    this.push(e);
    callbackFunction(e);
}

#9


0  

A lot better way is to use the fact that those methods modify array length. The way to take advantage of that is quite simple (CoffeeScript):

更好的方法是使用这些方法修改数组长度的事实。利用它的方法非常简单(CoffeeScript):

class app.ArrayModelWrapper extends Array
  constructor: (arr,chName,path)->
    vl  = arr.length
    @.push.apply(@,arr)
    Object.defineProperty(@,"length",{
      get: ->vl
      set: (newValue)=>
        console.log("Hello there ;)")
        vl = newValue
        vl
      enumerable: false
    })

#10


0  

If you want to do it on a single array :

如果要在单个阵列上执行此操作:

var a = [];

a.push = function(item) {
    Array.prototype.push.call(this, item);
    this.onPush(item);
};

a.onPush = function(obj) {
    // Do your stuff here (ex: alert(this.length);)
};

#11


0  

for debugging purpose you can try. And track the calling function from the call stack.

为了调试目的,你可以尝试。并从调用堆栈跟踪调用函数。

yourArray.push = function(){debugger;}

#1


23  

You could use an 'eventify' function that overrides push in the passed array.

你可以使用'eventify'函数来覆盖传入数组中的push。

var eventify = function(arr, callback) {
    arr.push = function(e) {
        Array.prototype.push.call(arr, e);
        callback(arr);
    };
};

In the following example, 3 alerts should be raised as that is what the event handler (callback) does after eventify has been called.

在下面的示例中,应该引发3个警报,因为这是在调用eventify之后事件处理程序(回调)所执行的操作。

var testArr = [1, 2];

testArr.push(3);

eventify(testArr, function(updatedArr) {
  alert(updatedArr.length);
});

testArr.push(4);
testArr.push(5);
testArr.push(6);

#2


22  

The only sensible way to do this is to write a class that wraps around an array:

唯一明智的做法是编写一个包装数组的类:

function EventedArray(handler) {
   this.stack = [];
   this.mutationHandler = handler || function() {};
   this.setHandler = function(f) {
      this.mutationHandler = f;
   };
   this.callHandler = function() { 
      if(typeof this.mutationHandler === 'function') {
         this.mutationHandler();
      }
   };
   this.push = function(obj) {
      this.stack.push(obj);
      this.callHandler();
   };
   this.pop = function() {
      this.callHandler();
      return this.stack.pop();
   };
   this.getArray = function() {
      return this.stack;
   }
}

var handler = function() {
   console.log('something changed');
};

var arr = new EventedArray(handler);

//or 

var arr = new EventedArray();
arr.setHandler(handler);


arr.push('something interesting'); //logs 'something changed'

#3


13  

try this:

var MyArray = function() { };
MyArray.prototype = [];
MyArray.prototype.push = function() {
    console.log('push now!');
    for(var i = 0; i < arguments.length; i++ ) {
        Array.prototype.push.call(this, arguments[i]);
    }
};

var arr = new MyArray();
arr.push(2,3,'test',1);

you can add functions at after pushing or before pushing

你可以在推或推之前添加功能

#4


3  

Why not just do something like this?

为什么不做这样的事情呢?

Array.prototype.eventPush = function(item, callback) {
  this.push(item);
  callback(this);
}

Then define a handler.

然后定义一个处理程序

handler = function(array) {
    console.log(array.length)
}

Then use the eventPush in the place that you want a specific event to happen passing in the handler like so:

然后在你希望特定事件发生的地方使用eventPush,如下所示:

a = []
a.eventPush(1, handler);
a.eventPush(2, handler);

#5


2  

I'd wrap the original array around a simple observer interface like so.

我将原始数组包装在一个简单的观察者界面周围。

function EventedList(list){
    this.listbase = list;
    this.events = [];
}

EventedList.prototype.on = function(name, callback){
    this.events.push({
        name:name,
        callback:callback
    });
}

//push to listbase and emit added event
EventedList.prototype.push = function(item){
    this.listbase.push(item);
    this._emit("added", item)
}

EventedList.prototype._emit = function(evtName, data){
    this.events.forEach(function(event){
        if(evtName === event.name){
            event.callback.call(null, data, this.listbase);
        }
    }.bind(this));
}

Then i'd instantiate it with a base array

然后我用基数组实例化它

    //returns an object interface that lets you observe the array
    var evtList = new EventedList([]);

    //attach a listener to the added event
    evtList.on('added', function(item, list){
         console.log("added event called: item = "+ item +", baseArray = "+ list);
    })

    evtList.push(1) //added event called: item = 1, baseArray = 1
    evtList.push(2) //added event called: item = 2, baseArray = 1,2
    evtList.push(3) //added event called: item = 3, baseArray = 1,2,3

you can also extend the observer to observe other things like prePush or postPush or whatever events you'd like to emit as you interact with the internal base array.

您还可以扩展观察者以观察其他内容,例如prePush或postPush,或者当您与内部基本阵列交互时要发出的任何事件。

#6


1  

This will add a function called onPush to all arrays, by default it shouldn't do anything so it doesn't interfere with normal functioning arrays.

这将向所有数组添加一个名为onPush的函数,默认情况下它不应该执行任何操作,因此它不会干扰正常运行的数组。

just override onPush on an individual array.

只需覆盖单个数组上的onPush。

Array.prototype.oldPush = Array.prototype.push;
Array.prototype.push = function(obj){
    this.onPush(obj);
    this.oldPush(obj);
};
//Override this method, be default this shouldnt do anything. As an example it will.
Array.prototype.onPush = function(obj){
    alert(obj + 'got pushed');
};

//Example
var someArray = [];

//Overriding
someArray.onPush = function(obj){
    alert('somearray now has a ' + obj + ' in it');
};

//Testing
someArray.push('swag');

This alerts 'somearray now has a swag in it'

这个警告'某些人现在有一个赃物'

#7


1  

Sometimes you need to queue things up before a callback is available. This solves that issue. Push any item(s) to an array. Once you want to start consuming these items, pass the array and a callback to QueuedCallback(). QueuedCallback will overload array.push as your callback and then cycle through any queued up items. Continue to push items to that array and they will be forwarded directly to your callback. The array will remain empty.

有时您需要在回调可用之前排队。这解决了这个问题。将任何项目推送到数组。一旦您想开始使用这些项目,请将数组和回调传递给QueuedCallback()。 QueuedCallback会将array.push重载为您的回调,然后遍历任何排队的项目。继续将项目推送到该阵列,它们将直接转发到您的回调。该数组将保持为空。

Compatible with all browsers and IE 5.5+.

兼容所有浏览器和IE 5.5+。

var QueuedCallback = function(arr, callback) {
  arr.push = callback;
  while (arr.length) callback(arr.shift());
};

Sample usage here.

此处使用示例。

#8


0  

Untested, but I am assuming something like this could work:

未经测试,但我假设这样的东西可以工作:

Array.prototype.push = function(e) {
    this.push(e);
    callbackFunction(e);
}

#9


0  

A lot better way is to use the fact that those methods modify array length. The way to take advantage of that is quite simple (CoffeeScript):

更好的方法是使用这些方法修改数组长度的事实。利用它的方法非常简单(CoffeeScript):

class app.ArrayModelWrapper extends Array
  constructor: (arr,chName,path)->
    vl  = arr.length
    @.push.apply(@,arr)
    Object.defineProperty(@,"length",{
      get: ->vl
      set: (newValue)=>
        console.log("Hello there ;)")
        vl = newValue
        vl
      enumerable: false
    })

#10


0  

If you want to do it on a single array :

如果要在单个阵列上执行此操作:

var a = [];

a.push = function(item) {
    Array.prototype.push.call(this, item);
    this.onPush(item);
};

a.onPush = function(obj) {
    // Do your stuff here (ex: alert(this.length);)
};

#11


0  

for debugging purpose you can try. And track the calling function from the call stack.

为了调试目的,你可以尝试。并从调用堆栈跟踪调用函数。

yourArray.push = function(){debugger;}