Прикрепить прослушиватель событий к массиву для события Push()
Есть ли способ узнать, когда пользователь поместил (через push()
) элемент в массив?
В основном у меня есть асинхронный скрипт, который позволяет пользователю выдвигать команды в массив. Как только мой скрипт загружается, он выполняет команды. Проблема в том, что пользователь может добавить дополнительные команды в массив после того, как мой скрипт уже запущен, и я должен быть уведомлен, когда это произойдет. Имейте в виду, что это обычный массив, который пользователь создает самостоятельно. Google Analytics делает нечто похожее на это.
Я также нашел это, где я думаю, что Google делает это, но я не совсем понимаю код:
Aa = function (k) {
return Object.prototype[ha].call(Object(k)) == "[object Array]"
Я также нашел отличный пример, который, кажется, охватывает основы, но я не могу заставить мой добавленный метод push работать правильно:http://jsbin.com/ixovi4/4/edit
Ответы
Ответ 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;}