我正在尝试给我的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
答案 0 :(得分:5)
您在此处发布的代码无效,因为您使用IIFE来包装对象,setInterval
无法访问movingMenu
。但是,你在jsfiddle中的代码是正确的。您可以对IIFE进行解包,或将setInterval
放入IIFE,或者返回暴露move
函数的对象。您只需要确保movingMenu
可以访问move
或setInterval
。
使用this
在您的函数中获取该菜单的参考,其attribute
为movingMenu
,而不是variable
。
改变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;
注意在我的代码段中,我修改了您的代码,使menu
属性非静态。这将处理从菜单中添加或删除的项目。