JavaScript:定义函数和实例化对象的顺序

JavaScript:定义函数和实例化对象的顺序,javascript,Javascript,我对定义函数和实例化对象的顺序有疑问,请参见: 我现在只是在玩弄一个想法,但我碰到了这堵墙,我不知道这个问题是否有简单的解决办法。基本上,我有一个对象,在另一个对象上有一些方法,但这个另一个对象包含对第一个对象的引用,因此无论我实例化/定义的顺序如何,我都会得到一个错误,因为其中一个没有加载: var router = { update: function(event, from, to) { window.location.hash = "#/" + to;

我对定义函数和实例化对象的顺序有疑问,请参见:

我现在只是在玩弄一个想法,但我碰到了这堵墙,我不知道这个问题是否有简单的解决办法。基本上,我有一个对象,在另一个对象上有一些方法,但这个另一个对象包含对第一个对象的引用,因此无论我实例化/定义的顺序如何,我都会得到一个错误,因为其中一个没有加载:

  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 
    }
  });

感谢您的帮助。

出现时间问题似乎是因为您指定的回调之一是
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.

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

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

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

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

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();
}

依赖项修复可以简单到:

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),
}

还有可能重复,这里有一个关于require.js的好问题需要检查。您是在JSFIDLE的范围内完成这些工作,还是在其他地方进行测试?我在没有JSFIDLE的浏览器中进行测试。。。看起来像是黑客,不是吗我最近的编辑对你不起作用吗?它实际上会在它尝试回调之前抛出错误,所以当我对它进行注释时,它会给出一个错误,这里有一个更为JSFIDLE友好的JSFIDLE,它的新版本可以工作:啊,如果我这样做了,按钮将被启用,并允许用户在不应该的时候最初访问back按钮。感谢所有的帮助/想法,但似乎我不得不推迟初始化FSM,分配回调,然后初始化FSM,这是迄今为止我看到的唯一没有bug的方法。不管怎样,这只是为了测试一个想法,没有什么东西能吸引广泛的观众(我不这么认为!)