The scope of the movingMenu
object is limited to the anonymous function that wraps it... 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 = {..} })
Invocation: (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
. Nothing oustide of foo
knows anything about movingMenu
. This is the idea of scope. movingMenu
exists in the scope of foo
.
So to get the functionality of movingMenu
outside the scope of foo
, we can return movingMenu
from foo
. What this does is makes the return value of foo
the movingMenu
object, like so...
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
.
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.
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
. Really, could use the name movingMenu
instead of menuHandler
, I just think it's less confusing this way.
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? 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.
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. 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. This will handle items being added or removed from the menu.