【问题标题】:Advanced constructs in JavascriptJavascript 中的高级构造
【发布时间】:2011-08-23 18:12:39
【问题描述】:

我在 github 上发现了一个有趣的项目,它在浏览器中处理 pdf rendering

我试图阅读代码,因为我对这个主题很感兴趣,但我意识到我的 javascript 知识很差(不足)。

有如下结构:

var Obj = (function() {
    function constructor(type, value) {
    this.type = type;
    this.value = value;
    }

    constructor.prototype = {
    };

    var types = [
    "Bool", "Int", "Real", "String", "Name", "Null",
    "Array", "Dict", "Stream", "Ref",
    "Cmd", "Error", "EOF", "None"
    ];

    for (var i = 0; i < types.length; ++i) {
    var typeName = types[i];
    constructor[typeName] = i;
    constructor.prototype["is" + typeName] =
    (function (value) {
     return this.type == i &&
     (typeof value == "undefined" || value == this.value);
     });
    }

    constructor.prototype.lookup = function(key) {
      function lookup(key) {
        if (!(this.value.contains(key)))
          return Obj.nullObj;
        return this.value.get(key);
      }
    }

    Object.freeze(constructor.trueObj = new constructor(constructor.Bool, true));
    Object.freeze(constructor.falseObj = new constructor(constructor.Bool, false));
    Object.freeze(constructor.nullObj = new constructor(constructor.Null));
    Object.freeze(constructor.errorObj = new constructor(constructor.Error));
    Object.freeze(constructor.prototype);
    Object.freeze(constructor);

    return constructor;
})();

您可以在上面的链接中看到更多。

您能否告诉我一些可以学习的资源,以便能够轻松理解项目中的代码,甚至更好地为以后的项目做出贡献?

【问题讨论】:

    标签: javascript data-structures control-structure language-construct


    【解决方案1】:

    在外面工作,这里的第一个重要概念是匿名函数。

    var Obj = (function() { /* do work */})();
    

    简单地说,我们正在创建一个匿名函数,然后立即执行它, 并将匿名函数的返回值分配给名为 Obj 的变量。

    为什么会有人想要这样做?

    在这种情况下,它用于创建私有范围。 javascript中的局部变量是 作用于定义它们的函数。例如:

    function test() {
        var a = 10;
    }
    
    // a is not defined here.
    

    在最后一个例子中,a 实际上只存在于函数的作用域内 定义它。 Javascript 在这方面有点棘手,因为省略了var 关键字,你可以定义一个全局变量。

    所以在你给出的例子中,他们使用这个匿名函数来构建一个 一些变量的作用域,这些变量将被使用,但最终会被抛出 函数执行完毕后立即离开。

    下一步:

    var Obj = (function() {
        function constructor(type, value) {
            this.type = type;
            this.value = value;
        }
    
        // SNIP
    })();
    

    这将创建一个名为 constructor 的新函数。重要的是要注意 javascript 函数 是first-class objects,这意味着它们的工作方式与任何其他对象非常相似,并且可以分配 到一个变量。此函数的作用域是匿名函数。所以试图让constructor出去 其功能范围的一面,是行不通的。例如

    var Obj = (function() {
        function constructor(type, value) {
            this.type = type;
            this.value = value;
        }
    
        // SNIP
    })();
    
    typeof(constructor) // <= undefined
    

    到目前为止,如果您要执行到目前为止的代码片段,那么 Obj 将是未定义的。现在 让我们先跳过一点结束,看看返回。

    var Obj = (function() {
        function constructor(type, value) {
            this.type = type;
            this.value = value;
        }
    
        // SNIP
    
        return constructor;
    })();
    

    所以当匿名函数被调用时,它会返回构造函数。这个函数得到 传回的分配给Obj。这将构造函数交还给本地范围之外 函数,并赋值给变量。然后你就可以调用它了

    var Obj = (function() {
        function constructor(type, value) {
            this.type = type;
            this.value = value;
        }
    
        // SNIP
    
        return constructor;
    })();
    
    var o1 = new Obj("t", "v");
    o1.type // <= "t"
    o1.value // <= "v"
    

    接下来我们有一条有趣的线

    var Obj = (function() {
        function constructor(type, value) {
        this.type = type;
        this.value = value;
        }
    
        constructor.prototype = { };
    
        // SNIP
    
        return constructor;
    })();       
    

    这会将构造函数的原型设置为空对象。解释原型的细节是 这篇文章的一些范围,但过于简单的是原型定义了实例方法 可用于由构造函数创建的对象。一个单一的“原型”在之间共享 并将用于定义可用于构造的对象的方法 打电话给new Obj()

    接下来我们有一个本地定义的数组

    var types = [
        "Bool", "Int", "Real", "String", "Name", "Null",
        "Array", "Dict", "Stream", "Ref",
        "Cmd", "Error", "EOF", "None"
    ];
    

    请记住,因为我们在函数内部,所以这个变量被绑定在外部匿名函数的范围内。

    接下来我们遍历那个数组,并设置一些东西。

    for (var i = 0; i < types.length; ++i) {
        var typeName = types[i];
        constructor[typeName] = i;
        constructor.prototype["is" + typeName] =
            (function (value) {
                return this.type == i &&
                (typeof value == "undefined" || value == this.value);
            });
    }
    

    这里发生了两件有趣的事情。首先,它设置了constructor 的“静态”属性,然后 在构造函数的原型上创建一个新函数。此函数称为"is" + typeName。所以我们应该 生成一堆实例方法,命名为:“isBool”、“isInt”、“isReal”等。

    constructor.prototype.lookup = function(key) {
      function lookup(key) {
        if (!(this.value.contains(key)))
          return Obj.nullObj;
        return this.value.get(key);
      }
    }
    

    接下来我们定义另一个名为lookup的实例方法并做一些工作。

    最后,我们从构造函数中创建一些静态属性,并将它们冻结(因此它们不能被更改或扩展)

    说完之后,Obj 应该指向一个构造函数,我们应该可以这样说:

    var myType = new Obj("MyType",undefined);
    myType.isBool(undefined) //instance method
    Obj.Bool  // static property
    

    无论如何,我希望这有助于解释一些正在使用的概念。大外卖应该 是 function 可以用来控制范围,并且函数是 First-class 函数,并且可以传递 像变量一样。您还可以使用点表示法 (obj.property) 或方括号表示法引用对象的属性 (obj["property"])。

    还有很多东西要学,所有的书建议都在这个线程中很可靠。如果没有提到我 也会推荐Eloquent JavaSript by Haverbeke

    【讨论】:

    • 感谢您的精彩解释。实际上,我正在阅读 Eloquent javascript,但现在我开始而不是 Javascript: The Good Parts,正如 dmc 建议的那样。看来我喜欢简明扼要的书,所以我可以把更多的时间花在编码上而不是阅读上。您的解释非常适合学习。
    【解决方案2】:

    Douglas Crockford's book JavaScript: The Good Parts 是一个了解 JavaScript 强大功能的好地方,同时让您远离丑陋(或完全危险)的部分。 His website 还收集了有关该语言的有趣文章。我推荐两者。

    【讨论】:

    • 这本书正是我想要的。谢谢你。我接受32bitkid 的回答,因为他做得很好,但你的建议也属于公认的答案,并且正在进一步扩展知识。
    • 好吧,@32bitkid 很好地解释了您的代码 sn-p。我很高兴您发现我的回答很有用。祝你好运!
    【解决方案3】:

    【讨论】:

    • 这些链接以前不能正常工作,但现在它们可以正常工作,而且它们非常好,一开始比其他答案中建议的书籍更容易理解。谢谢他们
    【解决方案4】:
    【解决方案5】:

    我发现 Douglas Crockford(http://www.crockford.com/)、John Resig(http://ejohn.org/blog/) 的博客对中高级概念很有用。查看其他人的代码(就像您正在做的一样)也会有所帮助。归根结底,尽管没有什么比实际尝试这个概念更好的了,但值得信赖的 Firebug 控制台仍然是最好的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-04
      • 1970-01-01
      • 1970-01-01
      • 2015-03-06
      • 2014-09-02
      相关资源
      最近更新 更多