模块模式 - 如何将一个模块的代码拆分成不同的js文件?

Boy*_*ang 11 javascript module-pattern requirejs revealing-module-pattern

对于模块模式,我做的事情如下:

(function(namespace) {
    // tons of code
    // blabla
})(window.myGlobalNamespace);
Run Code Online (Sandbox Code Playgroud)

如何拆分代码?我可以想到几种方法,比如使用命名空间的层次结构,或者扩展外部的对象window.myGlobalNamespace.additionalFunc = function () {//blabla}.还有什么其他方法?优缺点都有什么?哪一个被认为是更好的做法?

这两个答案都提出了RequireJS.能否解释一下RequireJS如何解决这些问题:

first.js:

(function(context) {
    var parentPrivate = 'parentPrivate';
})(window.myGlobalNamespace);
Run Code Online (Sandbox Code Playgroud)

second.js:

(function(context) {
    this.childFunction = console.log('trying to access parent private field: ' + parentPriavte);
}(window.myGlobalNamespace.subNamspace);
Run Code Online (Sandbox Code Playgroud)

main.js:

window.myGlobalNamespace.subNamspace.childFunction(); // doesn't work
Run Code Online (Sandbox Code Playgroud)

人们可以做到

window.myGlobalNamespace.subNamspace.childFunction = function() {alert("a new function");}
Run Code Online (Sandbox Code Playgroud)

改变我的代码的行为!

这里有两个问题:

  1. 我们不能拥有儿童可以访问的字段,但不能访问外部公众(即受保护的).有没有办法实现这一目标?

  2. 如果没有,意味着如果我们想要访问,我们需要将其公之于众.然后用户将能够修改它!

更重要的是,所有公共功能都可以更改和替换.我不希望这种情况发生.

我不知道RequireJS如何解决这些问题.有人可以解释一下吗?

Jos*_*son 38

只有两种方法可以将JavaScript转换为HTML:

  1. 内联 -<script> some JavaScript </script>
  2. 链接 -<script src='main.js'></script>

我知道这是显而易见的,但我们需要接下来的共同点.;)

JavaScript没有能力将其他JavaScript文件"导入"它自己.所有"导入"都在HTML中完成.您可以通过以下几种方式实现:

  • 每个单独链接到HMTL
  • 通过一些JavaScript 动态链接它们

    var script = document.createElement("script");
    script.src = "all.js";
    document.documentElement.firstChild.appendChild(script);
    
    Run Code Online (Sandbox Code Playgroud)
  • RequireJS这样的图书馆.RequireJS使用异步模块定义(AMD)API.它是用于定义模块的JavaScript机制,以便可以异步加载模块及其依赖项.

考虑将JavaScript分离为单独文件的原因是重要的.

  • 可维护性 - 一次一件作品变得更容易
  • 可读性 - 如果一切都在一个大文件中,很难看出它是什么
  • 分工 - 让多个开发人员处理多个文件而不是一个大文件更容易
  • 重用 - 您的所有功能都可以分解为高度紧密的模块

单独的JavaScript文件不会使事物变得私密,闭包会使事物变得私密.

现在,考虑在一天结束时,一切都准备好生产,你可以做的最好的事情是通过将它们全部组合到一个文件来优化你的JavaScript,这样用户只有一个文件可供下载.


在JavaScript中处理私有变量时,您将在某个时候想要访问它们.

  • 公共职能 - 可以改变.
  • 特权函数 - 可以访问私有变量的公共函数.
  • 但是,如果函数位于实例中,则只能在每个对象中进行更改.

让我用一些代码来说明.

module-test.html和main.js(合并first.js,second.js和main.js以便于测试)

var MODULE = (function () {
	//Private variables
	var privateParent,
	    app;
	
	privateParent = 'parentPrivate';
	
	return app = {
		//Privileged method
		getPrivateParent: function() {
			return privateParent;
		}
	};
}());

MODULE.sub = (function (parentApp) {
	//Private variables
	var childMessage,
	    Constr;
	
	childMessage = ' - trying to access parent private field: ' + parentApp.getPrivateParent();  //prints parentPrivate

	Constr = function () {
		this.childF = this.childFunction();
	};
	
	//Constructor
	Constr.prototype = {
		constructor: MODULE.sub,
		version: "1.0",
		childFunction: function () {
			$("#testing-div").append(childMessage + "</br>");
		}
	};
	return Constr;
	
}(MODULE));
	
//We could just as easily print to the console, but the 'append' allows us to display the results on the page.

$("#testing-div").append("This first part shows what <b>does not work</b>; everything is 'undefined'. " + "</br>");
$("#testing-div").append("You are unable to access the var or func directly. " + "</br>");
$("#testing-div").append("MODULE.privateParent = " + MODULE.privateParent + "</br>");
$("#testing-div").append("MODULE.app = " + MODULE.app + "</br>");
$("#testing-div").append("MODULE.sub.childMessage = " + MODULE.sub.childMessage + "</br>");
$("#testing-div").append("MODULE.sub.Constr = " + MODULE.sub.Constr + "</br>");
$("#testing-div").append("MODULE.sub.childFunction = " + MODULE.sub.childFunction + "</br>");
$("#testing-div").append("END lesson. You must access childFunction() through the <b>new</b> operator." + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
	
$("#testing-div").append("Let's see if making an instance of the Object works" + "</br>");
var test = new MODULE.sub();
test.childFunction(); //run the method
$("#testing-div").append("Looks like it did!!!!" + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
	
$("#testing-div").append("Now let's try to change the childFunction() ?" + "</br>");
test.childFunction = function() {$("#testing-div").append(" - This is a new function." + "</br>");}
test.childFunction(); // altered version
$("#testing-div").append("Looks like it was changed. :(" + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
$("#testing-div").append("Does it stay changed?" + "</br>");
var test2 = new MODULE.sub();
test2.childFunction(); // doesn't work
$("#testing-div").append("NO, it was only Overriden in the 'test' Object.  It did not effect all the other new objects. :)" + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Module Test</title>
<!-- 	<script data-main="scripts/main" src="scripts/require.js"></script> -->
</head>
<body>
    <h1>This is a test for separate Modules and Private variables.</h1>
    <div id="testing-div">
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="main.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
---

如果您想使用RequireJS来完成上述任务,您可以.RequireJS使用您和我已经使用的模块模式.如果要分离文件,则有两种方法可以执行此操作.

  1. 正常 - 只需将JS文件设置为使用RequireJS,只需稍加修改就可以放入上面的模块.
  2. 杠杆 - 使用RequireJS的Module特性作为模块来设置闭包.这看起来可能更难以弄清楚,但从长远来看它可能更有效.

注意:我还没有机会比较这两个选项,但希望将它们包括在内以保证完整性.


您可能会发现以下参考资料有用: