Подтвердить что ты не робот

Прикрепить прослушиватель событий к массиву для события Push()

Есть ли способ узнать, когда пользователь поместил (через push()) элемент в массив?

В основном у меня есть асинхронный скрипт, который позволяет пользователю выдвигать команды в массив. Как только мой скрипт загружается, он выполняет команды. Проблема в том, что пользователь может добавить дополнительные команды в массив после того, как мой скрипт уже запущен, и я должен быть уведомлен, когда это произойдет. Имейте в виду, что это обычный массив, который пользователь создает самостоятельно. Google Analytics делает нечто похожее на это.

Я также нашел это, где я думаю, что Google делает это, но я не совсем понимаю код:

    Aa = function (k) {
        return Object.prototype[ha].call(Object(k)) == "[object Array]"

Я также нашел отличный пример, который, кажется, охватывает основы, но я не могу заставить мой добавленный метод push работать правильно:http://jsbin.com/ixovi4/4/edit

4b9b3361

Ответ 1

Вы можете использовать функцию "eventify", которая переопределяет push в переданном массиве.

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

В следующем примере должны быть подняты 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

Единственный разумный способ сделать это - написать класс, который обтекает массив:

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

попробуйте это:

var MyArray = function() { };
MyArray.prototype = Array.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);

вы можете добавить функции после нажатия или перед нажатием

Ответ 4

Почему бы просто не сделать что-то подобное?

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

Затем определите обработчик.

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

Затем используйте eventPush в том месте, где вы хотите, чтобы определенное событие произошло в обработчике следующим образом:

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

Ответ 5

Я бы обернул исходный массив вокруг простого интерфейса наблюдателя.

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));
}

Затем я создам его с помощью базового массива

    //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

вы также можете расширить наблюдателя, чтобы наблюдать за другими вещами, такими как prePush или postPush, или любыми событиями, которые вы хотите испускать при взаимодействии с внутренним базовым массивом.

Ответ 6

Это добавит функцию под названием onPush ко всем массивам, по умолчанию она не должна ничего делать, чтобы она не мешала нормальным функциям.

просто переопределить 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');

В этом предупреждении "somearray теперь имеет swag в нем"

Ответ 7

Иногда вам нужно поставить очередь в очередь до того, как будет доступен обратный вызов. Это решает эту проблему. Нажмите любой элемент в массив. Когда вы захотите начать использовать эти элементы, передайте массив и обратный вызов QueuedCallback(). QueuedCallback будет перегружать array.push в качестве вашего обратного вызова, а затем циклически перемещаться по любым поставленным в очередь элементам. Продолжайте нажимать элементы на этот массив, и они будут перенаправлены непосредственно на ваш обратный вызов. Массив останется пустым.

Совместимость со всеми браузерами и IE 5.5 +.

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

Пример использования здесь.

Ответ 8

Неподтвержденный, но я предполагаю, что это может сработать:

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

Ответ 9

Лучше всего использовать тот факт, что эти методы изменяют длину массива. Способ воспользоваться этим довольно прост (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

Если вы хотите сделать это в одном массиве:

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

для цели отладки, которую вы можете попробовать. И отслеживать функцию вызова из стека вызовов.

yourArray.push = function(){debugger;}