简体   繁体   English

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

[英]Invoking jQuery function every x second (object literal pattern)

I'm trying to give my jQuery a bit more a structure with a basic object literal pattern and encountered an issue with calling my custom move function as per the following. 我试图给我的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);

I'm trying to call this function every second but the calling part itself doesn't seem to work. 我试图每秒调用一次此函数,但是调用部分本身似乎不起作用。 I suspect that the variable movingMenu is maybe outside the scope that within window.setInterval it doesn't have a clue in which object this function belongs to? 我怀疑变量movingMenu可能不在window.setInterval范围内,它不知道此函数属于哪个对象?

Demo is available JSFiddle 演示可用JSFiddle

  1. The code you post here would not work, as you use an IIFE to wrap the object, the setInterval can't access movingMenu . 您在此处发布的代码无法正常工作,因为您使用IIFE包装对象,因此setInterval无法访问movingMenu However, your code in jsfiddle is correct. 但是,您在jsfiddle中的代码是正确的。 You can either dewrap the IIFE, or put the setInterval into the IIFE, or return a object that exposed the move function. 您可以解包IIFE,或将setInterval放入IIFE,或返回暴露了move函数的对象。 You just need to ensure that movingMenu , or the move is accessible to setInterval . 您只需要确保movingMenusetInterval可以访问此move

  2. Use this to get the ref of that menu in your function, as its an attribute of movingMenu , not an variable . 使用this来获取函数中该菜单的引用,因为它是movingMenuattribute ,而不是variable

Altered jsfiddle 改变了jsfiddle

Move everything out of IIFE: 将所有内容移出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);

Move setInterval into IIFE as well: 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);
})();

Yes, you are right, the variable movingMenu is out of scope. 是的,您是对的,变量movingMenu不在范围内。

Also, to use the property menu inside the method you need to use this.menu . 另外,要在方法内部使用属性menu ,您需要使用this.menu There is no object scope in JavaScript, so even if you are "inside" the object, you can't directly access the object properties. 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);

})();

You're correct about movingMenu being unavailable. 您对movingMenu不可用是正确的。 To get around this, you want to set your module to a variable and return whatever you want to access outside of the module. 为了解决这个问题,您需要将模块设置为变量,并返回要在模块外部访问的任何内容。

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

edit: whoops, I read object literal pattern then saw the module pattern and ran in the wrong direction. 编辑:糟糕,我阅读了对象文字模式,然后看到了模块模式,并以错误的方向运行。

The scope of the movingMenu object is limited to the anonymous function that wraps it... function() { var movingMenu = { ... } } . movingMenu对象的范围仅限于将其包装的匿名函数... function() { var movingMenu = { ... } }

You're using a syntax that is allowing you to define that anonymous function, and then invoke or call it immediately. 您使用的语法允许您定义该匿名函数,然后立即调用或调用它。

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

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

This would be the same as if you said... 就像你说的一样...

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

So, in that context, movingMenu is a variable that is defined inside another function, foo . 因此,在这种情况下, movingMenu是在另一个函数foo定义的变量。 Nothing oustide of foo knows anything about movingMenu . foo一无所知对movingMenu This is the idea of scope . 这就是范围的想法。 movingMenu exists in the scope of foo . movingMenu存在于foo的范围内。

So to get the functionality of movingMenu outside the scope of foo , we can return movingMenu from foo . 因此, movingMenu的功能超出foo的范围,可以从foo返回movingMenu What this does is makes the return value of foo the movingMenu object, like so... 这样做是使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()

Then, you can use menuHandler like you would movingMenu . 然后,您可以像menuHandler一样使用movingMenu

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

Since you're declaring the function anonymously (not giving it a name, like I did with foo ), and then you're invoking it right away, you want to store the return value right away, since you won't be able to invoke that method again. 由于您要匿名声明该函数(不像我对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()

Then, you can use menuHandler like you were trying to use movingMenu . 然后,您可以像尝试使用menuHandler一样使用movingMenu Really, could use the name movingMenu instead of menuHandler , I just think it's less confusing this way. 确实,可以使用名称movingMenu代替menuHandler ,我只是认为这种方式不太容易混淆。

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

So putting it altogether, with the anonymous function... 因此,将其与匿名功能放在一起...

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

So why would you do this? 那为什么要这么做呢? Why not just make movingMenu public and invoke it directly, instead of wrapping it in an anonymous method and exposing it as a return value from that method? 为什么不只是将movingMenu公开并直接调用它,而不是将其包装在一个匿名方法中并作为该方法的返回值公开呢? The reason again has to do with scope. 原因再次与范围有关。 By limiting the scope and controlling what is exposed, you can actually create (somewhat, details are beyond the scope of this question) private properties in js. 通过限制范围并控制公开的内容,您实际上可以在js中创建(某种程度上,细节超出了此问题的范围)。

For example... 例如...

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;  

    })();

From this example, you can now see that movingMenu is exposed (as menuHandler ), and it has the ability to use the private variable privateCounter , however, privateCounter is not exposed. 从此示例中,您现在可以看到movingMenu被公开(作为menuHandler ),并且具有使用私有变量privateCounter的能力,但是privateCounter没有公开。 So basically this pattern makes everything private initially, so you can expose just what you want to be public. 因此,基本上,此模式最初将所有内容设为私有,因此您可以公开想要公开的内容。

 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> 

NOTE In my snippet I've modified your code to make the menu property non-static. 注意在我的代码段中,我已经修改了您的代码,以使menu属性变为非静态。 This will handle items being added or removed from the menu. 这将处理从菜单添加或删除的项目。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM