本节将介绍如何支持“simplified CommonJS wrapper”模块,node.js的SJS模块实质在内部包一层构成一个SCW模块,而seajs提倡的 CMD 也源自于它。
//http://blog.millermedeiros.com/amd-is-better-for-the-web-than-commonjs-modules/ //一个遵循SCW规范的模块,SCW是CommonJS关于模块定义的一个子规范 define(function(require, exports, module){ var myLib = require('myPackage/myLib'); function foo(){ console.log('foo'); myLib.doSomething(); } //expose module API exports.foo = foo; });
我们也可以顺带看一下老外正在搞到的es6中有关模块的部分:
//http://calculist.org/blog/2012/03/29/synchronous-module-loading-in-es6/ import $ from "jquery.js"; $('myelement').style({ 'background-color': 'yellow' }) // http://wiki.ecmascript.org/doku.php?id=harmony:private_name_objects import Name from "@name"; var key = new Name(); ... Proxy.create({ ... get: function(receiver, name) { if (name === key.public) ... else ... }, ... });
它们通过引入新的关键字方式来处理,这不是个好主意,估计以后像访问器一下,加到Object或某个对象上成为一个方法进行调用。
如果浏览器真的支持它们,我们可以通过特征侦测,然后整到我的加载器内部就行了,保证全平台前后兼容!
好了,我们回归正题,怎么通过mass.js实现SCW规范的模块加载,之前两节是前端社区提供的AMD规范,而SCW规范则是兼容node.js的重要手段。
建立一个index.html,内容如下:
<!DOCTYPE HTML> <html> <head> <title>SAW规范的模块加载例子 by 司徒正美</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style> html,body{ height:100%; } </style> <script src="mass.js"> </script> <script> //加载当前目录下的more目录的aaa.js $.require("./more/aaa", function(a){ $.log(a) }) </script> </head> <body> <h1>SAW规范的模块加载例子 by 司徒正美</h1> </body> </html>
mass.js应该与此html文件在同一目录下,然后在此目录下建more目录,然后再建aaa.js文件,内容如下:
define(function(require,exports,module){ var b = require("./bbb").bbb; $.log(b); $.log(exports); $.log(module) return "aaa" })
我们可以看到依赖模块的加载放到模块工厂内部了,这意味着在前端如何要实现这语法只能提前把这个函数的源码全部分析一遍,用正则把require语句抽取出来,也意味着它无法做到按需加载,所有if分支都无法阻挡正则的解析。
再建一个bbb.js,它与aaa.js是在同一目录下
define(function(){ var c = require("./more/ccc").ccc; $.log("已加载bbb模块") $.log(c) exports.bbb = "bbb" })
我们会看到它bbb.js依赖于ccc.js,我们要记住一点,依赖模块总是根据父模块的位置定位的。谁是引入者(或被依赖者),谁就是父模块。相反,依赖模块是被引入者的子模块,我们可以在module中得到它们的关系,里面有parent与children属性。bbb.js已经在more目录下了,ccc那个路径意味着它还要在此more目录下再建一个more目录,里面有个ccc.js文件。
define(function(){ $.log("已加载ccc模块") exports.ccc = "ccc" })
好了,我们用firefox打开index.html,在firebug看到以下输出:
我们再在firebug中展开那个Object{xxxxxxx}什么的,可以看到module对象里面的内容:
你们可以把module, exports, require为模块工厂内部的变量就行了,参数里面不写它们也完全OK,你总是能引用到它们的!