重写并添加到我的命名空间的JavaScript库

时间:2013-04-19 17:09:12

标签: javascript javascript-namespaces

我打开了一个名为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来回忆所有关于此类方法的私有和公共函数的讨论,但有些事情让我很困惑:

  1. 为什么外部匿名函数有参数以及它们将在何处使用?

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

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

  4. 也许我们可以更好地重写这一切与否? 我刚刚阅读How do I declare a namespace in JavaScript?,我发现Jaco Pretorius回答得非常好,我可以重写这个并将其添加到我的命名空间,如下所示:

    (函数(myGibberishAES){

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

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

  5. 这是否可以接受可接受的编码标准?

    谢谢!

1 个答案:

答案 0 :(得分:2)

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

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

  1. 如果定义了exports函数,那么我们可能正在使用node.js
  2. 如果有一个名为define的函数,并且它有一个名为amd的属性,那么这意味着我们正在使用AMD。
  3. 如果上述情况均不成立,我们不会使用任何内容,因此我们应将此附加到根对象,在此特定情况下将为window
  4. 这个函数的参数是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.jsamdWeb.js的更简单变体的组合) ,还要看AMD on requireJS