在Javascript中关闭的细微差别

时间:2015-01-21 03:27:43

标签: javascript functional-programming closures lexical-closures

我一直在努力理解Javascript的功能组合技术,我想出了一个玩具准MVC的工作代码来演示我的问题:

var modelFactory = function() {
  var _state = false;
  var _listener = null;

  var _updateView = function() {
    _listener(_state);
  };

  var _interface = {
    registerListener: function(listen) {
      _listener = listen;
    },
    eventHandler: function() {
      _state = true;
      _updateView();
    }
  };
  return _interface;
};

var viewFactory = function(updateFunction) {
  var _hook = $('<div class="box"></div>');
  $('body').append(_hook);

  var _interface = {
    getHook: function getHook() {
      return _hook;
    },
    update: updateFunction(_hook)
  };

  return _interface;
};


var main = function() {

  var modelInstance = modelFactory();

  var viewInstance = viewFactory(
    function bindHook (hook) {
      return function bindState (state) {
        if (state === true) {
          hook.addClass("red");
        } else {
          hook.removeClass("red");
        }
      };
    }
  );

  modelInstance.registerListener(viewInstance.update);
  modelInstance.eventHandler(); // When called, mutates _state, then calls the listener
};

$(document).ready(main);
.box {
  background-color: #000;
  width: 100px;
  height: 100px;
}
.red {
  background-color: #f00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

在这段代码中,我传入了一个绑定“hook”变量的函数,并返回一个范围保留该绑定的函数。这是我的问题的关键。

我希望能够抽象出“钩子”绑定,所以我可以将“状态”绑定函数传递给一个函数,然后执行“钩子”绑定。我还没有想出如何使用Javascript提供的后期绑定工具(应用/调用此方法)。我可以传递对象引用以保持状态,并完成工作,但我对解决此问题的更多功能方法感兴趣。所以:

a)有没有办法做我正在尝试用Javascript中的基本闭包做的事情,如果有的话,或者

b)如果我应该使用后期绑定的“这个”方法,那么最好的方法是什么?我假设这是在Javascript中推广函数状态的经过验证的方法,但是我写的代码最终没用。

1 个答案:

答案 0 :(得分:0)

我想你只想在你的viewFactory

中创建闭包
function viewFactory(updateFunction) {
  var _hook = $('<div class="box"></div>');
  return {
    getHook: function getHook() {
      return _hook;
    },
    update: function(state) {
      return updateFunction(_hook, state)
    }
  };
}

…
var viewInstance = viewFactory(function bindState(hook, state) {
  hook[state ? "addClass" : "removeClass"]("red");
});
$('body').append(viewInstance.getHook());
modelInstance.registerListener(viewInstance.update);

创建此闭包只是partial application的一种情况,当然可以在辅助函数中抽象出来(被称为update: partial(updateFunction, _hook))。

您还可以使用bind作为函数this绑定的部分应用程序。假设你想把钩子作为this传递,你要写

update: function(state) {
  return updateFunction.call(_hook, state); // notice the similarity to above
}

或仅(等效)

update: updateFunction.bind(_hook)