1

我打开了一个名为 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){...}

我什至可以通过调用所有返回的函数 aspublic和其余的 as来回忆有关这种方法的私有和公共函数的所有讨论,private但有些事情让我很困惑:

  1. 为什么外部匿名函数有参数,它们将在哪里使用?

  2. 而不是使用(function(){//put my code here...}());作者(function(root, factory){//some code...}(this, function(){//main code here...}));,这是为什么呢?

  3. 在问题 (2) 上,我可以看到两个参数thisfunction(){//main code here...}作为参数传递给外部匿名函数来代替rootand factory。所以,root变成了this!但是,现在this指的是哪里?

  4. 也许我们可以更好地重写这一切?我刚刚阅读了如何在 JavaScript 中声明命名空间?我发现 Jaco Pretorius 的回答非常棒,我可以重写这个并将其添加到我的命名空间中,如下所示:

    (函数(myGibberishAES){

    //这里的主要代码...

    }(window.myGibberishAES = window.myGibberishAES || {}));

可以接受的编码标准吗?

谢谢!

4

1 回答 1

2

这种格式称为 UMD(通用模块定义),它是一种编写代码的方式,可以使用和不使用 AMD(异步模块定义),以及使用和不使用 Node.js。

在第一个匿名函数中,代码正在检查我们所处的环境。

  1. 如果exports定义了一个函数,那么我们可能正在使用 node.js
  2. 如果有一个名为 的函数define,并且它有一个名为 的属性amd,那么这意味着我们正在使用 AMD。
  3. 如果上述情况都不成立,我们没有使用任何东西,所以我们应该将它附加到根对象,在这种特殊情况下将是window.

这个函数的参数是this(将是window)和一个基本上是工厂的函数,即,它是实际定义对象的代码。通常(没有 UMD),它看起来像这样:

var myModule = (function() {
    ...
}();

所以现在factory基本上是这个函数,它返回你的模块/对象。module.exports如果您使用的是 node.js,则可以将该对象分配给该对象,或者如果您使用的define是 AMD,则可以将其传递给函数,否则您可以简单地将其附加到根对象 ( window)。

至于您的重写问题,您可能不想这样做,因为常规的 JavaScript 命名空间声明模式不适用于 node.js 和 AMD。与 requireJS 一起使用的 AMD 允许您指定和管理依赖项,因此如果有人使用 requireJS,这允许他们非常轻松地导入此模块。这基本上是满足三种不同用例和框架的一种方式。

如果你没有使用 node.js 或 requireJS,你不需要重写任何东西,因为GibberishAES它将是一个附加到的全局对象,window所以你可以直接使用它。

有关更多信息,请查看GitHub 上的UMD,它有一堆模式(您正在查看的是 的组合nideAdapter.js和更简单的变体amdWeb.js),还可以查看requireJS 上的 AMD

于 2013-04-19T17:21:33.363 回答