每隔x秒调用jQuery函数(对象文字模式)

时间:2015-08-31 14:13:32

标签: javascript jquery

我正在尝试给我的jQuery更多一个带有基本对象文字模式的结构,并且遇到了按照以下方式调用我的自定义move函数的问题。

(function() {

  var movingMenu = {
    menu: $('.nav').children('li'),

    move: function() {
      menu.each(function() {
        $(this).animate({
            top: '+=50'
        }, 200);
      });   
    }
  };  

})();

window.setInterval(function(){
  movingMenu.move();
}, 1000);

我试图每秒调用此函数,但调用部分本身似乎不起作用。我怀疑变量movingMenu可能在window.setInterval范围之外,它不知道这个函数属于哪个对象?

演示可用JSFiddle

4 个答案:

答案 0 :(得分:5)

  1. 您在此处发布的代码无效,因为您使用IIFE来包装对象,setInterval无法访问movingMenu。但是,你在jsfiddle中的代码是正确的。您可以对IIFE进行解包,或将setInterval放入IIFE,或者返回暴露move函数的对象。您只需要确保movingMenu可以访问movesetInterval

  2. 使用this在您的函数中获取该菜单的参考,其attributemovingMenu,而不是variable

  3. 改变jsfiddle

    将所有内容移出IIFE:

    var movingMenu = {
        menu: $('.nav').children('li'),
    
        move: function () {
        //  VVVV you need to use this to reference to `movingMenu`, so this.menu is the referenced `li`s.
            this.menu.each(function () {
                $(this).animate({
                    top: '+=50'
                }, 200);
            });
        }
    };
    
    window.setInterval(function () {
        movingMenu.move();
    }, 1000);
    

    setInterval移至IIFE:

    (function(){
        var movingMenu = {
            menu: $('.nav').children('li'),
    
            move: function () {
            //  VVVV you need to use this to reference to `movingMenu`, so     this.menu is the referenced `li`s.
                this.menu.each(function () {
                    $(this).animate({
                        top: '+=50'
                    }, 200);
                });
            }
        };
    
        window.setInterval(function () {
            movingMenu.move();
        }, 1000);
    })();
    

答案 1 :(得分:2)

是的,你是对的,变量movingMenu超出了范围。

此外,要在方法中使用属性menu,您需要使用this.menu。 JavaScript中没有对象范围,所以即使你是"内部"对象,您无法直接访问对象属性。

(function() {

  var movingMenu = {
    menu: $('.nav').children('li'),

    move: function() {
      // use "this" to access properties
      this.menu.each(function() {
        $(this).animate({
            top: '+=50'
        }, 200);
      });   
    }
  };  

  // use the variable inside the scope
  window.setInterval(function(){
    movingMenu.move();
  }, 1000);

})();

答案 2 :(得分:1)

你对movingMenu不可用是正确的。要解决这个问题,您需要将模块设置为变量并返回模块外部要访问的任何内容。

var movingMenu = (function() {

  return {
    menu: $('.nav').children('li'),

    move: function() {
      this.menu.each(function() {
        $(this).animate({
            top: '+=50'
        }, 200);
      });   
    }
  };

})();

window.setInterval(function(){
  movingMenu.move();
}, 1000);

编辑:whoops,我读取对象文字模式,然后看到模块模式并向错误的方向运行。

答案 3 :(得分:-1)

movingMenu对象的范围仅限于包装它的匿名函数... function() { var movingMenu = { ... } }

您正在使用允许您定义匿名函数的语法,然后立即调用或调用它。

声明:(function() { var movingMenu = {..} })

调用:(function() { ... })()

这就像你说的那样......

var foo = function() { var movingMenu = {...} };
foo();

因此,在该上下文中,movingMenu是在另一个函数foo中定义的变量。 foo没有任何关于movingMenu的任何事情。这是scope的想法。 movingMenu存在于foo范围内。

为了使movingMenu的功能超出foo的范围,我们可以从movingMenu返回foo。这样做会使foo movingMenu对象的返回值如此......

var foo = function() { 
    var movingMenu = {
        menu: $('.nav').children('li'),

        move: function() {
          menu.each(function() {
            $(this).animate({
               top: '+=50'
            },200);
          });   
        }
      };

      return movingMenu;  

    };

var menuHandler = foo(); // save movingMenu, returned from foo()

然后,您可以menuHandler使用movingMenu

window.setInterval(function () {
   menuHandler.move();
}, 1000);

由于您以匿名方式声明了该功能(没有给它起名称,就像我对foo所做的那样),然后您立即调用它,您希望存储返回值马上,因为你再也无法调用那个方法了。

var foo = function() { 
    var movingMenu = {
        menu: $('.nav').children('li'),

        move: function() {
          menu.each(function() {
            $(this).animate({
               top: '+=50'
            },200);
          });   
        }
      };

      return movingMenu;  

    };

var menuHandler = foo(); // save movingMenu, returned from foo()

然后,您可以使用menuHandler,就像您尝试使用movingMenu一样。实际上,可以使用名称movingMenu代替menuHandler,我只是觉得这种方式不那么令人困惑。

window.setInterval(function () {
   menuHandler.move();
}, 1000);

完全放在匿名函数中......

var menuHandler = (function() { 
    var movingMenu = {
        menu: $('.nav').children('li'),

        move: function() {
          menu.each(function() {
            $(this).animate({
               top: '+=50'
            },200);
          });   
        }
      };

      return movingMenu;  

    })();

window.setInterval(function () {
   menuHandler.move();
}, 1000);

那你为什么要这样做?为什么不直接使movingMenu公开并直接调用它,而不是将其包装在匿名方法中并将其作为该方法的返回值公开?原因再次与范围有关。通过限制范围和控制暴露的内容,您实际上可以在js中创建(有些细节超出了本问题的范围)私有属性。

例如......

var menuHandler = (function() {
    // ADDED NEXT LINE FOR EXAMPLE:
    var privateCounter = 0; 
    var movingMenu = {
        menu: $('.nav').children('li'),

        move: function() {
          menu.each(function() {
            $(this).animate({
               top: '+=50'
            },200);

            // ADDED NEXT LINE FOR EXAMPLE:
            console.log("Count is now: " + (privateCounter++).toString());
            // look at the console tab of browser's dev tools (F-12 on windows)
          });   
        }
      };

      return movingMenu;  

    })();

在此示例中,您现在可以看到movingMenu已公开(menuHandler),并且它可以使用私有变量privateCounter,但privateCounter没有暴露。因此,基本上这种模式最初会使所有内容变为私有,因此您可以公开您想要公开的内容。



var menuHandler = (function() {
  var privateCounter = 0,
    menu = (function() {
      return $('.nav').children('li');
    })();

  var movingMenu = {
    move: function() {
      menu.each(function() {
        $(this).animate({
          top: '+=50'
        }, 200);
      });

      console.log("Count is now: " + (privateCounter++).toString());
    }
  };

  return movingMenu;
})();

setInterval(function() {
  menuHandler.move();
}, 1000);

.nav {
  position: absolute;
}
.nav li {
  position: relative;
  top: 0;
}
ul {
  list-style: none;
}
ul li {
  display: inline-block;
  background: red;
  border-radius: 50%;
  color: white;
  width: 50px;
  height: 50px;
  text-align: center;
  line-height: 3;
}

<ul class="nav">
  <li>Look</li>
  <li>Play</li>
  <li>Eat</li>
  <li>See</li>
</ul>
&#13;
&#13;
&#13;

注意在我的代码段中,我修改了您的代码,使menu属性非静态。这将处理从菜单中添加或删除的项目。