속깊은 자바- 함수 기반 데코레이터

by parksd

HTML

<script src="https://getfirebug.com/firebug-lite-debug.js"></script>

JavaScript

(function() {
  var monitorTool,
    car,
    wrapperFunction;

  // 모니터링 툴?
  monitorTool = (function() {
    var functionSequence = [];
    return {
      // 데코레이터에 대한 이름과 함수를 저장해 놓는다.
      decorate: function(name, func) {
        functionSequence.push({
          name: name,
          func: func
        });
      },
      // 각 데코레이터 함수를 한번씩 실행한다.
      monitor: function(func) {
        var length = functionSequence.length;
        for (i = 0; i < length; i++) {
          functionSequence[i].func.apply(this, arguments);
        }
      }
    };
  }());

  // 다음 3개를 데코레이터로 정의한다.
  monitorTool.decorate("before", function(func) {
    console.log(func.name + " function has started at " + Date.now());
  });
  monitorTool.decorate("decorated", function(func) {
    func.apply(this, Array.prototype.slice(arguments, 1));
  });
  monitorTool.decorate("after", function(func) {
    console.log(func.name + " function has finished at " + Date.now());
  });

  // wrapperFunction은 각 데코레이터 함수를 한번씩 호출하는 것.
  wrapperFunction = monitorTool.monitor;

  car = {
    beep: function beep() {
      console.log("원래의 beep()");
    },
    brake: function brake() {   
      console.log("원래의 brake()");
    },
    accelerator: function accelerator() {
      console.log("원래의 accelerator()");
    }
  };

  // 함수를 wrapper로 wrapping한다.
  function wrap(func, wrapper) {
    // 원래 함수를 args[0]에 넣고, wrapper 3개를 호출하는 함수를 리턴한다.
    // 지금 호출되는게 아니다.
    return function() {
      var args = [func].concat(Array.prototype.slice.call(arguments));
      return wrapper.apply(this, args);
    };
  }

  // 객체가 가진 모든 함수를 wrapper로 wrapping한다.
  function wrapObject(obj, wrapper) {
    console.log("333");
    var prop;
    // obj의 속성들에 대해서, function일 경우에만 wrap() 한 다음 다시 저장.
    for (prop in obj) {
      if (obj.hasOwnProperty(prop) && typeof obj[prop] === "function") {
        obj[prop] = wrap(obj[prop], wrapper);
      }
    }
  }

  // car 객체를 wrapperFunction 함수로 wrapping하는데, 그 것은 MonitorTool.monitor 함수이다.
  //...