Change Event を遅延させて発火させる

Event(input) を利用して、文字の連続入力が終了したら、一定時間後に change イベントを発火させます

<!DOCTYPE html>
<html lang="ja">
<meta charset="UTF-8">

<body>
<h1>Input 要素の change イベントを遅延させて発火させる</h1>
<p><input id="A"></p>

<script>

{
  // input イベントを監視して、変更があったら change イベントを発火させる
  
  class delayChangeEvent {
    constructor (target, delayTime = 300, cbFunc = null) {
      if (! target)
        throw new Error ('要素がありません');

      this.target = target;
      this.delay  = delayTime; //遅延時間(ms)
      this.cbFunc = cbFunc; //その時に実行する関数
      this.disabled = false; //この値を true にすると実行されなくなる
      this.timeId   = null; //setTimeout で使用する
      this.value    = target.value;
      
      // input event を監視する
      target.addEventListener ('input', this, false);
    }
    
    
    //イベントハンドラ
    handleEvent (event) {
      if (! this.disabled) {
        switch (event.type) {
        
        //input event を監視する
        case 'input' :
          if (this.timerId)
            clearTimeout (this.timerId);//タイマーを解除
          this.timerId = setTimeout (this.execute.bind (this), this.delay);//タイマー設定
          break;
        }
      }
    }
    

    //change イベントを発火させる
    execute () {
      if (! this.disabled) {
        this.timerId = null;
        if (this.value !== this.target.value) {

          let
            e = this.target,
            event = e.ownerDocument.createEvent ('HTMLEvents');
          
          event.initEvent ('change', true, true);

          //change イベントの前に コールバックを実行する
          if ('function' === typeof this.cbFunc)
            this.cbFunc (this.target);

          e.dispatchEvent (event);
  
        }
      }
    }
  }
  
  this.delayChangeEvent = delayChangeEvent;
}


function hoge (e) {
  //先頭の空白削除と2文字以上続く空白は1文字の空白とする
  e.value = e.value.replace (/^(\s*)|\s+(?=\s)/g, '');
}


let a = document.getElementById('A');
//a.addEventListener ('change', hoge, false);

new delayChangeEvent (a, 400, hoge);


</script>