2013-07-24 5 views
1

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

function Counter() { 
    this.currentCount = 0; 
} 

Counter.prototype.start = function() { 
    setInterval(this.update, 1000); 
}; 

Counter.prototype.when = function(value, callback) { 
    callback(value); 
}; 

Counter.prototype.update = function() { 
    this.currentCount++; 
}; 

В моем сознании это будет работать примерно так.

var counter = new Counter(); 
counter.when(50, function(value) { 
    console.log('We arrived at ' + value + ', the requested value.'); 
}); 
counter.start(); 
+0

Что вы цените? пройденное время ? html input? ... –

+0

ну в этом примере он просто вернет значение, первоначально заданное для – Josh

ответ

1

Это просто хороший домашнее задание, я сделаю это для вас;) Пожалуйста, посмотрите на мое решение:

function Counter() { 
    this.currentCount = 0; 
    this.conditions = []; 
    this.interval = undefined; 
} 

Counter.prototype.start = function() { 
    if (!this.interval) { 
     var that = this; 
     this.interval = setInterval(function() { 
      that.update(); 
     }, 1000); 
    } 
}; 

Counter.prototype.stop = function() { 
    if (this.interval) { 
     clearInterval(this.interval); 
     this.interval = undefined; 
    } 
    this.currentCount = 0; 
}; 

Counter.prototype.when = function(value, callback) { 
    var that = this; 
    this.conditions.push(function() { 
     if (that.currentCount === value) { 
      callback.call(that, value); 
     } 
    }); 
}; 

Counter.prototype.update = function() { 
    this.currentCount++; 
    for (var i = 0, l = this.conditions.length; i < l; i++) { 
     var condition = this.conditions[i]; 
     condition(); 
    } 
}; 

var counter = new Counter(); 
counter.when(50, function(value) { 
    console.log('We arrived at ' + value + ', the requested value.'); 
}); 
counter.when(60, function (value) { 
    console.log('Stop at ' + value + '!'); 
    this.stop(); 
}); 
counter.start(); 

и это fiddled!

Другой ответ здесь дал хороший аргумент в сокрытии частных переменных, но реализовал его немного смущенно, так что это еще один способ сделать его похожим. Вместо общих функций прототипа это использует функции экземпляра. Некоторые могут сказать, что это требует большего объема памяти, но я не считаю, что это важно, и позволяет легко иметь рядовых в реальной функции конструктора.

var Counter = function() { 
    var that = this, currentCount = 0, 
     conditions = [], interval; 
    var update = function() { 
     currentCount++; 
     for (var i = 0, l = conditions.length; i < l; i++) { 
      var condition = conditions[i]; 
      condition(); 
     } 
    }; 
    this.start = function() { 
     if (!interval) { 
      interval = setInterval(function() { 
       update.call(that); 
      }, 1000); 
     } 
    }; 
    this.when = function (value, callback) { 
     conditions.push(function() { 
      if (currentCount === value) { 
       callback.call(that, value); 
      } 
     }); 
    }; 
    this.stop = function() { 
     if (interval) { 
      clearInterval(interval); 
      interval = undefined; 
     } 
     currentCount = 0; 
    }; 
}; 

var counter = new Counter(); 
counter.when(50, function(value) { 
    console.log('We arrived at ' + value + ', the requested value.'); 
}); 
counter.when(60, function (value) { 
    console.log('Stop at ' + value + '!'); 
    this.stop(); 
}); 
counter.start(); 

посмотреть его fiddled!

Обратите также внимание, что в обоих примерах counter является instanceof Counter и Object,
тогда Counter является instanceof Function и Object (почему мне нравится писать так много кода;))

+0

Ницца, мне нужно учиться и играть с этим немного больше. Мне нравится, что он может содержать несколько условий. – Josh

+0

Надеюсь, вы не путаетесь с 'that' и' callback.call' - 'that' требуется, потому что во вложенных функциях' this' не является «счетчиком» объекта. он делает обратный вызов с 'this === that' (счетчик). как вы видите в функции setInterval, я фактически использую 'this.update', поэтому' update' уже называется «в контексте' this' », и больше не нужно делать' this.update.call (that) '. Я противопоставляю непосредственно 'setInterval (this.update, 0)' вы бы потеряли 'this'. WAH странно объяснять, но легко, когда вы читаете о вызове функции и применяете. – metadings

+0

Я не смущен этим, если использовать lodash/подчеркивание, я думаю, что он также может быть привязан. Я согласен, что это может быть трудно объяснить, но ваш пример почти объясняет сам. – Josh

0

Для поддержки нескольких Whens:

Добавить массив Whens в своем классе:

function Counter() { 
    this.currentCount = 0; 
    this.whens = []; 
} 

Тогда пусть когда функция толчок, что:

Counter.prototype.when = function(value, callback) { 
this.whens.push({'time' : value, 'callback' : callback}); 
} 

И чек для них, когда они были обновлены:

Counter.prototype.update = function() { 
    this.currentCount++; 

    for(var w in this.whens) { 
     if(this.currentCount == this.whens[w].time) { 
      this.whens[w].callback(); 
     } 
    } 
} 
0

Попробуйте что-нибудь подобное:

function Counter(interval, val, func){ 
    this.currentCount = 0; 
    setInterval(function(){ 
    this.currentCount++; 
    if(this.currentCount === val)func(); 
    }, interval); 
} 
var nc = new Counter(1000, 50, function(){ 
    console.log('We have arrived at '+nc.currrentCount); 
}); 
0

Существует аргумент, чтобы сделать что-то вместо этого:

var Counter = (function() { 
    var update = function() { 
     var idx, callbacks; 
     this.currentCount++; 
     callbacks = this.callbacks[this.currentCount]; 
     if (callbacks) { 
      for (idx = 0; idx < callbacks.length; idx++) { 
       callbacks[idx](this.currentCount); 
      } 
     } 
    }; 
    var start = function() { 
     var counter = this; 
     setInterval(function() {update.call(counter)}, 1000); 
    }; 
    var when = function(count, callback) { 
     (this.callbacks[count] || (this.callbacks[count] = [])).push(callback); 
    }; 
    return function() { 
     var config = {currentCount: 0, callbacks: {}}; 
     this.start = function() {return start.call(config);}; 
     this.when = function(count, callback) { 
      return when.call(config, count, callback); 
     }; 
     // this.stop = ... // if desired 
    }; 
}()); 

Это несколько более интенсивный объем памяти, чем версия кода на основе прототипов. Я бы не использовал его для чего-то, где вы ожидали сотни тысяч или миллионы объектов. Но это имеет то преимущество, что оно действительно инкапсулирует данные, которые вы хотели бы скрывать, например, currentCount и список обратных вызовов. Он не предоставляет ненужную функцию update. И это не ужасно тяжелее прототипа. Каждый экземпляр имеет свои собственные функции start и when, но это только тонкие обертки вокруг общих функций.

Сложно добавить функцию stop к этому точно так же, если вы не возражаете против воздействия на результат setInterval. Но это выполнимо.

+0

Мне нравится аргумент, чтобы скрыть рядовых, но я думаю, вы сделали это слишком сложно. Не возвращайте анонимную функцию, но используйте конструкторную функцию more: создайте private 'var counter = this, currentCount = 0, conditions = {}, interval;', а затем просто выпустите 'this.start' и' this.when' , оставляя 'var update'. Затем вы также можете легко добавить 'this.stop', и вы получили реальную конструкторскую функцию, не подвергая текущему количеству, обновлению и т. Д.! – metadings

+0

см. [Скрипка] (http://jsfiddle.net/VeJG2/) для того, как я думаю реализовать его таким образом, как функцию-конструктор с частным и экземпляром вместо прототипа общих функций – metadings

+0

@metadings: Да, эта техника работает одинаково чтобы скрыть частные данные. Причина, по которой я использую тот, который я выбрал, состоит в том, чтобы уменьшить объем памяти в памяти каждого объекта Counter. В вашей версии каждый 'Counter' имеет целые копии функций' start' и 'when'; в моей, они имеют только тонкие оберточные функции вокруг общих функций. Это, вероятно, менее важно при таких небольших функциях, но в некоторых случаях это может иметь значение. Я тоже понял, что я глупо о «стоп». Это было легко реализовать здесь: http://jsfiddle.net/CrossEye/m9Xs2/ –

Смежные вопросы