需要 advise/help 来摆脱全局变量
Need advise/help on getting rid of global variables
是的,这是另一个关于全局变量的话题。我已经搜索了很多关于它们的信息。但是大多数主题只是关于为什么不使用全局变量,我确信我不应该,而且我更想知道如何不使用它们,而且我仍然不确定。
我正在做一个项目,它创造了奇迹,但我目前使用了大约 50 个全局变量,而且这个数字还在不断增加。现在我已经将内容拆分为多个 .js 文件。像 load_chunks.js、load_images.js、render_map.js、player_actions.js、input.js,根据它们的用途来扩展功能。我将所有全局变量都放在 settings.js.
中
目前我使用这些全局变量的原因如下:
1.基于其他一些加载后变化不大或根本没有变化的全局变量进行计算。通过执行一次并将其存储在全局变量中,我不再需要再次重复计算。如果我没有将它存储在(全局)变量中,Javascript 每秒必须进行多次计算,在某些情况下甚至每秒进行几千次。
2.当很多函数需要全局变量时。就像这个世界变量,我用它来保存世界外观的数据。这个变量是一个多维数组。例如世界[y][x]。 Load_chunks.js 向此变量添加更多数据,或者如果移动过远则删除数据。在 render_map.js 中也需要此变量来创建地图,在 player_action.js 中也需要此变量以查看您是否可以踩到该特定位置。
3.设置;因此,除非我在脚本中更改它们,否则变量中的数字将保持不变。我没有遍历我的脚本,也没有在长时间搜索并思考数字是什么后手动更改数字,而是将该数字放入 1 个变量中,并在我的脚本中多次调用该变量。在某些情况下,其他地方也需要这些变量。
我还想提一下,我不使用 类,也许是因为这个原因,我从来没有绕过使用全局变量...?
那么我该如何摆脱我的全局变量,或者我不应该吗?
我希望您能向我展示或为我写一个脚本示例(或 link 到它)说明我应该如何做。这是我最快的学习方式。
将变量放入函数闭包中
消除全局的一种常见方法是将 is 放在函数闭包中:
(function() {
var declareYourFormerGlobalHere = 0;
// put all code that uses the variable inside this closure
// the variable persists for this code to use, but is not actually global
})();
下面是一些用法示例:
// example keeping track of a running count and a cached DOM element
(function() {
var cntr = 0, obj = document.getElementById("test");
setInterval(function() {
++cntr;
if (obj.value < cntr) {
// do something
} else {
// do something else
}
}, 1000);
})();
// example keeping track of a time of last click
(function() {
var timeOfLastClick = 0;
document.getElementById("run").addEventListener("click", function(e) {
var now = new Date().getTime();
// only process click if more than 2 seconds have passed since last click
if (now - timeOfLastClick > 2000) {
// OK to process the click
}
timeOfLastClick = now;
});
})();
有时,您实际上可以像这样将所有代码或几乎所有代码封装在一个闭包中,并且所有当前全局变量都成为闭包内的局部变量,而不是实际的全局变量。 jQuery 使用这种技术来声明它使用的大量持久变量,none 其中实际上是全局范围的。
使用单个命名空间对象
另一种减少全局变量数量的常用方法是使用命名空间概念。在这个概念中,您声明一个单一的全局对象并将其他持久变量作为这个单一全局对象的属性。这仍然留给您一个全局变量,您可以在这个全局变量中拥有任意数量的属性。
var myNamepaceObject = {};
myNamespaceObject.var1 = "foo";
myNamespaceObject.var2 = "whatever";
此技术也被 jQuery 使用,因为 jQuery 提供的所有全局可访问功能都可以在 jQuery 对象之外使用,例如 jQuery.extend()
或 jQuery.contains()
. jQuery 公开单个全局变量,然后许多其他全局可访问函数可用作该单个全局对象的属性。
模块模式
通常称为 "module pattern" 的方法结合了上述两种技术,其中您有一个同时使用属性和闭包变量的模块变量。
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
您可以在这些参考资料中看到对此设计模式的讨论:
JavaScript Module Pattern: In-Depth
Learning Javascript - The Module Pattern
JavaScript module pattern with example
我以前遇到过同样的问题,但这是一个大问题,因为我们有第三方 javascript 代码,而且我们的代码存在于客户网站中,所以我们应该找到一种方法来省略全局变量的出现,所以简而言之:
使用 1 个全局变量命名空间并使所有其他命名空间成为它的属性:
GlobalVariable = {}
GlobalVariable.var1 = "var1"
GlobalVariable.var2 = "var2"
你还可以把它做的更有用,分成几组:
GlobalVariable.helper = {}
GlobalVariable.helper.var1 = "var1"
GlobalVariable.helper.var2 = "var2"
所以你可以在不同的组下使用相同的名字。
如果你想完全省略它,你可以使用:
(function(document, window) {
// all variables here is global only inside the scope
}(document, window));
I'm convinced that I shouldn't, and I am more wondering HOW not to use them, and that I'm still unsure about.
load_chunks.js, load_images.js, render_map.js, player_actions.js, input.js,
强烈暗示过程实现,即您的体系结构可能有几个功能部分,您在这些功能之间传递数据。这就是您的全局变量的来源。
So how do I get rid of my global variables (...)
要改变这一点,您需要以基于对象或组件的方法构建您的系统,即:
通过问题域中的对象封装数据+各自的功能,例如有一个 World
对象,其中包含 Avatar
、Buildings
、Airborne
对象等(或您的项目的任何内容)。
将问题域的逻辑与视图逻辑分开(例如使用 MVC architecture)
然后您的项目通过实质上在它们之间交换消息来组织视图和模型对象之间的交互。
为了促进这一点,我建议使用这些优秀的框架,或一些适合您 运行 时代环境的等效框架:
- requirejs - 将模块封装到全局管理的组件中
- backbonejs - 拥有一个高效的、经过验证的 model/view、class/object 模型(实际上是为与 REST 风格的后端一起使用而构建的,但这不是严格的要求)
代码结构
通常,我构建我的应用程序时,每个对象都有一个 .js 文件 component/module。这种意义上的模块包含 class 定义和相应的集合。这些模块由 requirejs 管理,class 定义使用 backbonejs 完成。
I hope you can show me or write for me a script example
/* define a class e.g. in someclass.js */
define(['backbone'], function($B) {
var SomeClass = $B.Model.extend({
// all instance variables, methods etc. follow
someVar : value,
someMethod : function() { ... },
});
return SomeClass;
});
/* use the class, e.g. in app.js */
require(['someclass'], function(SomeClass) {
var instance = new SomeClass({ initial model attributes });
var value = instance.get('attribute');
instance.someMethod();
...
});
是的,这是另一个关于全局变量的话题。我已经搜索了很多关于它们的信息。但是大多数主题只是关于为什么不使用全局变量,我确信我不应该,而且我更想知道如何不使用它们,而且我仍然不确定。
我正在做一个项目,它创造了奇迹,但我目前使用了大约 50 个全局变量,而且这个数字还在不断增加。现在我已经将内容拆分为多个 .js 文件。像 load_chunks.js、load_images.js、render_map.js、player_actions.js、input.js,根据它们的用途来扩展功能。我将所有全局变量都放在 settings.js.
中目前我使用这些全局变量的原因如下:
1.基于其他一些加载后变化不大或根本没有变化的全局变量进行计算。通过执行一次并将其存储在全局变量中,我不再需要再次重复计算。如果我没有将它存储在(全局)变量中,Javascript 每秒必须进行多次计算,在某些情况下甚至每秒进行几千次。
2.当很多函数需要全局变量时。就像这个世界变量,我用它来保存世界外观的数据。这个变量是一个多维数组。例如世界[y][x]。 Load_chunks.js 向此变量添加更多数据,或者如果移动过远则删除数据。在 render_map.js 中也需要此变量来创建地图,在 player_action.js 中也需要此变量以查看您是否可以踩到该特定位置。
3.设置;因此,除非我在脚本中更改它们,否则变量中的数字将保持不变。我没有遍历我的脚本,也没有在长时间搜索并思考数字是什么后手动更改数字,而是将该数字放入 1 个变量中,并在我的脚本中多次调用该变量。在某些情况下,其他地方也需要这些变量。
我还想提一下,我不使用 类,也许是因为这个原因,我从来没有绕过使用全局变量...?
那么我该如何摆脱我的全局变量,或者我不应该吗? 我希望您能向我展示或为我写一个脚本示例(或 link 到它)说明我应该如何做。这是我最快的学习方式。
将变量放入函数闭包中
消除全局的一种常见方法是将 is 放在函数闭包中:
(function() {
var declareYourFormerGlobalHere = 0;
// put all code that uses the variable inside this closure
// the variable persists for this code to use, but is not actually global
})();
下面是一些用法示例:
// example keeping track of a running count and a cached DOM element
(function() {
var cntr = 0, obj = document.getElementById("test");
setInterval(function() {
++cntr;
if (obj.value < cntr) {
// do something
} else {
// do something else
}
}, 1000);
})();
// example keeping track of a time of last click
(function() {
var timeOfLastClick = 0;
document.getElementById("run").addEventListener("click", function(e) {
var now = new Date().getTime();
// only process click if more than 2 seconds have passed since last click
if (now - timeOfLastClick > 2000) {
// OK to process the click
}
timeOfLastClick = now;
});
})();
有时,您实际上可以像这样将所有代码或几乎所有代码封装在一个闭包中,并且所有当前全局变量都成为闭包内的局部变量,而不是实际的全局变量。 jQuery 使用这种技术来声明它使用的大量持久变量,none 其中实际上是全局范围的。
使用单个命名空间对象
另一种减少全局变量数量的常用方法是使用命名空间概念。在这个概念中,您声明一个单一的全局对象并将其他持久变量作为这个单一全局对象的属性。这仍然留给您一个全局变量,您可以在这个全局变量中拥有任意数量的属性。
var myNamepaceObject = {};
myNamespaceObject.var1 = "foo";
myNamespaceObject.var2 = "whatever";
此技术也被 jQuery 使用,因为 jQuery 提供的所有全局可访问功能都可以在 jQuery 对象之外使用,例如 jQuery.extend()
或 jQuery.contains()
. jQuery 公开单个全局变量,然后许多其他全局可访问函数可用作该单个全局对象的属性。
模块模式
通常称为 "module pattern" 的方法结合了上述两种技术,其中您有一个同时使用属性和闭包变量的模块变量。
var MODULE = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
您可以在这些参考资料中看到对此设计模式的讨论:
JavaScript Module Pattern: In-Depth
Learning Javascript - The Module Pattern
JavaScript module pattern with example
我以前遇到过同样的问题,但这是一个大问题,因为我们有第三方 javascript 代码,而且我们的代码存在于客户网站中,所以我们应该找到一种方法来省略全局变量的出现,所以简而言之: 使用 1 个全局变量命名空间并使所有其他命名空间成为它的属性:
GlobalVariable = {}
GlobalVariable.var1 = "var1"
GlobalVariable.var2 = "var2"
你还可以把它做的更有用,分成几组:
GlobalVariable.helper = {}
GlobalVariable.helper.var1 = "var1"
GlobalVariable.helper.var2 = "var2"
所以你可以在不同的组下使用相同的名字。
如果你想完全省略它,你可以使用:
(function(document, window) {
// all variables here is global only inside the scope
}(document, window));
I'm convinced that I shouldn't, and I am more wondering HOW not to use them, and that I'm still unsure about.
load_chunks.js, load_images.js, render_map.js, player_actions.js, input.js,
强烈暗示过程实现,即您的体系结构可能有几个功能部分,您在这些功能之间传递数据。这就是您的全局变量的来源。
So how do I get rid of my global variables (...)
要改变这一点,您需要以基于对象或组件的方法构建您的系统,即:
通过问题域中的对象封装数据+各自的功能,例如有一个
World
对象,其中包含Avatar
、Buildings
、Airborne
对象等(或您的项目的任何内容)。将问题域的逻辑与视图逻辑分开(例如使用 MVC architecture)
然后您的项目通过实质上在它们之间交换消息来组织视图和模型对象之间的交互。
为了促进这一点,我建议使用这些优秀的框架,或一些适合您 运行 时代环境的等效框架:
- requirejs - 将模块封装到全局管理的组件中
- backbonejs - 拥有一个高效的、经过验证的 model/view、class/object 模型(实际上是为与 REST 风格的后端一起使用而构建的,但这不是严格的要求)
代码结构
通常,我构建我的应用程序时,每个对象都有一个 .js 文件 component/module。这种意义上的模块包含 class 定义和相应的集合。这些模块由 requirejs 管理,class 定义使用 backbonejs 完成。
I hope you can show me or write for me a script example
/* define a class e.g. in someclass.js */
define(['backbone'], function($B) {
var SomeClass = $B.Model.extend({
// all instance variables, methods etc. follow
someVar : value,
someMethod : function() { ... },
});
return SomeClass;
});
/* use the class, e.g. in app.js */
require(['someclass'], function(SomeClass) {
var instance = new SomeClass({ initial model attributes });
var value = instance.get('attribute');
instance.someMethod();
...
});