我遇到了以下问题。我的JavaScript结构如下所示。
我创建了一个包含所有控制器的对象。那些控制员有自己的责任。下面的代码属于首先调用的main.js
文件:
main.js
var App = {};
App.init = function() {
console.log('init');
App.uiController.init();
App.heroController.init();
}
在函数init()
中,我调用控制器的初始化器。
控制器对象如下所示:
uiController.js
App.uiController = {
root: 0,
init: function() {
// Development
console.log('init uiController');
root = this;
// Call functions
root.doSomething();
},
doSomething: function() {
}
}
加载完所有脚本后,我调用最后一个脚本init.js
:
init.js
App.init();
我的HTML标记如下所示:
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
</head>
<body>
<!-- // Start HTML \\ -->
<header id="header">
</header><!-- End header#header -->
<main class="main">
</main><!-- End main.main -->
<footer id="footer">
</footer><!-- End footer#footer -->
<!-- JavaScript -->
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="scripts/main.js" type="text/javascript"></script>
<script src="scripts/constructors/uiController.js" type="text/javascript"></script>
<script src="scripts/constructors/heroController.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="scripts/init.js" type="text/javascript"></script>
</body>
</html>
在函数中,我使用root
选择this
- 我当前所在的文件。通常我会在每个函数(作用域)中创建变量root
,并为其赋值this
。但我认为这可能会更好,在每个控制器对象中创建一个空根(全局),所以我只创建一次值root
,如下所示:
App.uiController = {
root: 0,
init: function() {
root = this;
// Call functions
root.doSomething();
},
doSomething: function() {
}
}
当我在root
函数中的console.log init()
时,它将返回一个对象,其中包含我现在所在的当前控制器中的所有函数,在上面的例子中App.uiController
。所以我认为这很有效,我只需为每个控制器创建并声明root
一次。所以我对heroController
执行了与uiController
相同的操作,并将变量root
记录到控制台。我接收到具有正确功能的不同对象:
但是,问题来了。在main.js
我在heroController.init()
之后调用uiController.init()
并且当uiController由控制器内的事件触发时,我在控制台中收到错误,uiController
内的某些函数无法正常工作期望。
当我删除每个控制器中的全局root
变量并在var root = this;
之类的init控制器中声明它时,代码将再次起作用。
有谁知道为什么上述设置无法正常运作?
期待您的回复。
根据Kingshuk basak的回答,我尝试了一些新的东西。以下是我的想法:
答案代码对我不起作用。它会给我错误:Uncaught ReferenceError: root is not defined
。当我使用我的问题中的代码并将root: 0
的{{1}}更改为heroController
并将两者都记录到控制台时:1
我得到console.log(App.uiController.root, App.heroController.root);
和{控制台中的{1}}。将它放在两个代码中的位置无关紧要,其他值不会覆盖这些值。这让我觉得很奇怪。
然后我尝试在0
中注释掉1
,然后在heroController
中注释掉console.log main.js
。我得到的值是root
,这是真的,但之后我在uiController.init() function
之后直接设置0
和console.log,值也是root = this;
而不是root.root
作为0
对象。这使得它更加令人困惑,为什么this
没有更改为对象而不是uiController
。此外,当我在文件root
中注释掉0
后,孔代码中只有一个root
。仅限heroController.init()
的Console.log将按预期提供main.js
对象。
最后,我也尝试了root
这两个函数:
uiController
当我这样做时,init()
的值对于每个控制器都是正确的,因为它将包含对象 - 该对象 - 其中包含所有相应的函数。但这会让我遇到与之前提到的相同的问题,即uiController没有按预期工作。
希望这能为每个人提供更多关于状态的信息,并为一个好的解决方案提供一些帮助!
答案 0 :(得分:6)
将root
设置为控制器的属性,以免您不必在控制器方法中键入var root = this
是没有用的。您应该在需要时var root = this
,因为该属性最终不是var root = this
的净收益。
你得到的第一个answer是部分答案。 kingshuk basak是正确的,你正在做的是在全局空间中设置一个root
变量。如果你这样做,请参阅:
function foo() {
something = 1;
}
您正在全局空间中设置something
。要使其成为您的函数的本地化,您需要var
:
function foo() {
var something = 1;
}
第一个代码段中缺少var
并不会使JavaScript将其解释为this.something
,即使该函数是原型的一部分。
kingshuk basak建议您使用this
将其作为控制器的一部分。这是有效的,但是你必须使用this
来访问它,因为这是JavaScript的工作方式。所以使用它的天真方式是:
uiController = {
root: 0,
init: function() {
this.root = this;
this.root.doSomething(); // You havve to use `this` here too!!
},
doSomething: function() {
this.root.somethingElse();
}
}
从你的问题所说,你只是想避免写var root = this
。所以root
永远不会改变。但想一想这一秒。
您正在做的是向root
添加名为this
的属性,该属性与this
具有完全相同的值。要访问与root
具有相同价值的this
,您需要拥有this
。因此,this.root
没有充分理由存在。如上所述,如果您执行this.root = this
,则每次访问都必须为this.root
,这样您就不会明显减轻您的负担。不仅如此,执行this.root.foo()
还需要执行额外的间接:root
必须首先从this
获取。
你可以这样做:
uiController = {
root: 0,
init: function() {
var root = this.root = this;
root.doSomething();
},
doSomething: function() {
var root = this.root;
root.somethingElse();
}
}
但同样,这并没有减轻负担。
您应该在需要时var root = this
。
答案 1 :(得分:2)
原因很简单。 uiController的'root'变量被heroController过度写入,因为它们都在全局命名空间中声明。为uiController和heroController尝试不同的名称root1和root2,它可以正常工作。
注意:理想情况下,您不应该污染全局命名空间以避免此类问题。必要时使用闭包。
这就是你要做的事情:
uiController = {
root: 0,
init: function() {
this.root = this;
// Call functions
root.doSomething();
},
doSomething: function() {
}
}