【问题标题】:JavaScript: Order of defining functions and instantiating objectsJavaScript:定义函数和实例化对象的顺序
【发布时间】:2013-02-10 00:55:05
【问题描述】:

我在定义函数和实例化对象的顺序上有问题,请参阅:JSFiddle

我现在只是在玩一个想法,但我碰到了这堵墙,我不知道是否有任何简单的解决方案可以解决这个问题。基本上我有一个在另一个对象上有一些方法的对象,但是这个另一个对象包含对第一个对象的引用,所以无论我实例化/定义什么顺序,我都会得到一个错误,因为一个或另一个尚未加载:

  var router = {
    update: function(event, from, to) {
      window.location.hash = "#/" + to;
      $("back-btn").disabled = fsm.can("back");  // *** And here I am referencing fsm
      $("next-btn").disabled = fsm.can("next");
    },
    location: window.location.hash.substring(2),
  }

  var fsm = StateMachine.create({
    initial: "intro",
    events: [

      // Next events and where to route based on our page
      { name: "next", from: "intro", to: "getname" },
      { name: "next", from: "getname", to: "welcome" },
      { name: "next", from: "welcome", to: "why" },

      // We can't go "back" from the initial route
      { name: "back", from: "getname", to: "intro" },
      { name: "back", from: "welcome", to: "getname" },
      { name: "back", from: "why", to: "welcome" } ],

    callbacks: {
      onintro  : router.update, //*** Here I am referencing the router object
      ongetname: router.update,
      onwelcome: router.update,
      onwhy    : router.update 
    }
  });

感谢您的帮助。

【问题讨论】:

标签: javascript


【解决方案1】:

您可以使用try/catch 来避免第一个未定义:

try {
    $("back-btn").disabled = fsm.can("back");
    $("next-btn").disabled = fsm.can("next");
} catch(e){}

此外,如果您在 JSFiddle 中测试所有内容,它会将您的 JS 包装到 window.onload 函数中。因此,当您单击按钮时,它们将尝试调用fsm.back()fsm.next(),其中fsm 是在window.onload 函数的范围内定义的。不在这些按钮可以访问的范围内。

【讨论】:

    【解决方案2】:

    似乎发生了计时问题,因为您指定的回调之一是onintro,它可能会立即运行。重构 onintro 回调的实现是否可行?你也许可以摆脱这样的事情:

    var router = {
        update: function(event, from, to) {
            window.location.hash = "#/" + to;
            $("back-btn").disabled = fsm.can("back");
            $("next-btn").disabled = fsm.can("next");
        },
        location: window.location.hash.substring(2),
    }
    
    var fsm = StateMachine.create({
        //...
    
        callbacks: {
            //onintro  : router.update, // Don't call this in the constructor...
            ongetname: router.update,
            onwelcome: router.update,
            onwhy    : router.update 
        }
    });
    
    router.update(); // Call it just after construct.
    

    【讨论】:

    • 它实际上在尝试回调之前就抛出了错误,所以当我将它注释掉时,它会给出一个错误,这是一个对 JSFiddle 更友好的 JSFiddle,它的新版本有效:jsfiddle.net/Yqdj5/1
    【解决方案3】:

    我必须在事后将回调分配给状态机对象,然后将初始化推迟到定义我的路由器对象之后:

    var fsm = StateMachine.create({
    
      //*** Here we set defer to true
      initial: { state: "intro", event: "init", defer: true },
      events: [
    
        // Next events and where to route based on our page
        { name: "next", from: "intro",   to: "getname" },
        { name: "next", from: "getname", to: "welcome" },
        { name: "next", from: "welcome", to: "why" },
    
        // We can't go "back" from the initial route
        { name: "back", from: "getname", to: "intro" },
        { name: "back", from: "welcome", to: "getname" },
        { name: "back", from: "why",     to: "welcome" } ],
    });
    
    window.onload = function() {
      var router = {
        update: function(event, from, to) {
          window.location.hash = "#/" + to;
          $("back-btn").disabled = fsm.cannot("back");
          $("next-btn").disabled = fsm.cannot("next");
        },
        location: window.location.hash.substring(2),
      }
    
      //*** And now we attach the callbacks since we have created the router object
      fsm.onintro = router.update, fsm.ongetname = router.update,
      fsm.ongetname = router.update, fsm.onwelcome = router.update,
      fsm.onwhy = router.update;
    
      //*** And call the init event!
      fsm.init();
    }
    

    还有fiddle

    【讨论】:

    • 嗯...看起来像个黑客,不是吗。 =/ 我最近的编辑不适合你吗?
    【解决方案4】:

    依赖修复可以很简单:

    var router = {
        update: function(event, from, to) {
            window.location.hash = "#/" + to;
            if(window.fsm) {
                $("back-btn").disabled = fsm.can("back");
                $("next-btn").disabled = fsm.can("next");
            }
        },
        location: window.location.hash.substring(2),
    }
    

    【讨论】:

    • 啊,如果我这样做了,按钮将被启用,并允许用户最初访问后退按钮,而他们不应该这样做。感谢所有帮助/想法,但似乎我将不得不推迟初始化 FSM,分配回调,然后初始化 FSM,这是迄今为止我看到的唯一没有错误的方法。无论如何,这只是为了测试一个想法,没有什么能引起广泛的观众(我不认为!)
    猜你喜欢
    • 2019-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    • 1970-01-01
    • 2015-01-20
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多