Javascript中的高级构造

xra*_*alf 3 javascript control-structure language-construct data-structures

我在github上找到了一个有趣的项目,它在浏览器中处理pdf渲染.

我试着阅读代码,因为我对这个主题感兴趣,但我意识到我的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;
})();
Run Code Online (Sandbox Code Playgroud)

您可以在上面的链接中看到更多这些内容.

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

J. *_*mes 6

在外面工作,这里的第一个重要概念是匿名功能.

var Obj = (function() { /* do work */})();
Run Code Online (Sandbox Code Playgroud)

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

为什么有人想要这样做?

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

function test() {
    var a = 10;
}

// a is not defined here.
Run Code Online (Sandbox Code Playgroud)

在最后一个示例中,a实际上只存在于定义它的函数范围内.Javascript在这方面有点棘手,因为通过省略var 关键字,您可以定义全局变量.

因此,在您给出的示例中,他们使用此匿名函数为将要使用的某些变量构建范围,但最终希望在函数执行完毕后立即丢弃.

下一个:

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

    // SNIP
})();
Run Code Online (Sandbox Code Playgroud)

这会创建一个名为的新函数constructor.重要的是要注意javascript函数是第一类对象,这意味着它们像任何其他对象一样工作,并且可以分配给变量.此函数的范围限定为匿名函数.因此,试图constructor摆脱其功能范围的一面是行不通的.例如

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

    // SNIP
})();

typeof(constructor) // <= undefined
Run Code Online (Sandbox Code Playgroud)

到目前为止,如果你到目前为止执行snippits,那么Obj将是未定义的.现在让我们先跳过一下,看看回报.

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

    // SNIP

    return constructor;
})();
Run Code Online (Sandbox Code Playgroud)

因此,当调用匿名函数时,它将返回构造函数.传回的此函数将被分配给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"
Run Code Online (Sandbox Code Playgroud)

接下来我们有一个有趣的路线

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

    constructor.prototype = { };

    // SNIP

    return constructor;
})();       
Run Code Online (Sandbox Code Playgroud)

这将构造函数的原型设置为空对象.解释原型的细节是本文的一小部分,但过分简单的是原型定义了构造函数创建的对象可用的实例方法.单个'原型'在它们之间共享,并将用于定义通过调用构造的对象可用的方法new Obj().

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

var types = [
    "Bool", "Int", "Real", "String", "Name", "Null",
    "Array", "Dict", "Stream", "Ref",
    "Cmd", "Error", "EOF", "None"
];
Run Code Online (Sandbox Code Playgroud)

请记住,因为我们在函数内部,此变量绑定在外部匿名函数的范围内.

接下来,我们遍历该数组,并设置一些东西.

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);
        });
}
Run Code Online (Sandbox Code Playgroud)

有趣的事情发生在这里.首先,它设置一个'静态'属性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);
  }
}
Run Code Online (Sandbox Code Playgroud)

接下来我们定义另一个被调用的实例方法,lookup并做一些工

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

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

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

无论如何,我希望这有助于解释一些正在使用的概念.最大的收获应该是a function可以用来控制范围,而且这些函数是一流的函数,可以像变量一样处理.您还可以使用点表示法(obj.property)或括号表示法(obj["property"])来引用对象的属性.

还有很多东西需要学习,所有的书籍建议在这个主题中都是可靠的.如果没有提到,我还会推荐Haverbeke的Eloquent JavaSript.