我打开了一个名为Jibberish (https://github.com/mdp/gibberish-aes)的javascript项目,我试图理解它的编码风格,我只是给出了它的开始和结束的一部分:
(function (root, factory) {
if (typeof exports === 'object') {
// Node.
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(factory);
} else {
// Browser globals (root is window)
root.GibberishAES = factory();
}
}(this, function () {
'use strict';
var Nr = 14,
/* Default to 256 Bit Encryption */
Nk = 8,
Decrypt = false,
enc_utf8 = function(s)
{
try {
return unescape(encodeURIComponent(s));
}
catch(e) {
throw 'Error on UTF-8 encode';
}
},
//...................................
return {
"size": size,
"h2a":h2a,
"expandKey":expandKey,
"encryptBlock":encryptBlock,
"decryptBlock":decryptBlock,
"Decrypt":Decrypt,
"s2a":s2a,
"rawEncrypt":rawEncrypt,
"rawDecrypt":rawDecrypt,
"dec":dec,
"openSSLKey":openSSLKey,
"a2h":a2h,
"enc":enc,
"Hash":{"MD5":MD5},
"Base64":Base64
};
}));
只是想知道它的用法:
// GibberishAES.enc(string, password)
// Defaults to 256 bit encryption
enc = GibberishAES.enc("This sentence is super secret", "ultra-strong-password");
alert(enc);
GibberishAES.dec(enc, "ultra-strong-password");
我可以看到一个最外面的自执行函数返回一个对象,在代码的末尾实际上是匿名的(!),这个对象的成员是自执行函数内部定义的函数,所以,属性"size"
指的是定义为函数表达式的function size()
:
size = function(newsize){...}
我甚至可以回忆起所有关于这种方法的私有和公共函数的讨论,将所有返回的函数调用为public
,其余的调用为private
,但有一些事情让我很困惑:
为什么外部匿名函数有参数,它们将在哪里使用?
作者用
(function(root, factory){//some code...}(this, function(){//main code here...}));
代替(function(){//put my code here...}());
,为什么?在问题(2)上,我可以看到两个参数
this
和function(){//main code here...}
作为参数传递给外部匿名函数,以代替root
和factory
。所以,root
变成了this
!但是,现在this
指的是什么?也许我们可以实现一个更好的重写这一切吗?我刚刚读了如何在JavaScript中声明命名空间?我发现Jaco Pretorius的答案非常棒,所以我可以重写这个并将其添加到我的命名空间,像这样:
(函数(myGibberishAES) {
//主代码
}(窗口。myGibberishAES =窗口。myGibberishAES || {}));
这符合可接受的编码标准吗?
谢谢!
这种格式被称为UMD(通用模块定义),它是一种编写代码的方法,可以使用或不使用AMD(异步模块定义),也可以使用或不使用Node。
在第一个匿名函数中,代码检查我们所处的环境。
- 如果定义了
exports
函数,那么我们可能使用node.js - 如果有一个名为
define
的函数,并且它有一个名为amd
的属性,那么这意味着我们正在使用AMD。 - 如果以上情况都不成立,我们不使用任何东西,所以我们应该将其附加到根对象,在这个特殊的情况下将是
window
。
这个函数的参数是this
(它将是window
)和一个基本上是工厂的函数,也就是说,它是实际定义对象的代码。通常情况下(没有UMD),它看起来像这样:
var myModule = (function() {
...
}();
所以现在factory
基本上是这个函数,它返回你的模块/对象。如果你使用node.js,这个对象可以分配给module.exports
,或者如果你使用AMD,它可以传递给define
函数,或者你可以简单地将它附加到根对象(window
)。
至于你的重写问题,你可能不想这样做,因为常规的JavaScript命名空间声明模式将无法与node.js和AMD一起工作。与requireJS一起使用的AMD允许你指定和管理依赖关系,所以如果有人正在使用requireJS,这允许他们很容易地导入这个模块。这基本上是一种满足三种不同用例和框架的方法。
如果你不使用node.js或requireJS,你不需要重写任何东西,因为GibberishAES
将是一个附加到window
的全局对象,所以你可以直接使用它。
要了解更多信息,请查看GitHub上的UMD,它有一堆模式(您正在查看的是nideAdapter.js
和amdWeb.js
的简单变体的组合),也可以查看AMD的requireJS。