Продвинутые конструкции в Javascript - PullRequest
3 голосов
/ 23 августа 2011

Я нашел один интересный проект на 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;
})();

Вы можете увидеть больше из них по ссылке выше.

Не могли бы вы порекомендовать мне некоторые ресурсы, которые нужно изучить, чтобы можно было легко понять код в проекте и, еще лучше, внести свой вклад позже в проект?

Ответы [ 5 ]

6 голосов
/ 23 августа 2011

Работая снаружи, первая важная концепция здесь - анонимные функции.

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 - это объекты первого класса , что означает, что они работают так же, как и любой другой объект, и могут быть назначены переменной.Эта функция ограничена анонимной функцией.Так что попытка вывести 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 может использоваться для управления областью видимости, и что функции являются функциями первого класса и могут передаваться как переменные.Вы также можете ссылаться на свойство объекта, используя точечную нотацию (obj.property) или скобочную нотацию (obj["property"]).

Существует множество других вещей, которые нужно изучить, и все предложения по книгам безупречныв этой теме.Если это не было упомянуто, я бы также порекомендовал Eloquent JavaSript от Haverbeke .

2 голосов
/ 23 августа 2011

Книга Дугласа Крокфорда JavaScript: The Good Parts - отличное место, чтобы оценить мощь JavaScript, отвлекая вас от уродливых (или совершенно опасных) частей, На его сайте также есть коллекция интересных статей о языке.Я рекомендую оба.

1 голос
/ 23 августа 2011

Я нахожу блоги Дугласа Крокфорда (http://www.crockford.com/), John Resig (http://ejohn.org/blog/)) полезными для промежуточных и продвинутых концепций. Также может быть полезно посмотреть на код других людей (так же, как вы делаете) В конце концов, хотя ничто не сравнится с проверкой концепции, и для этого надежная консоль Firebug по-прежнему является лучшей.

1 голос
/ 23 августа 2011

Я могу сослаться на некоторые ссылки

Могу ли я назвать функцию javascript и немедленно выполнить ее?

http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx

Я надеюсь, что вы можете учиться с ними

...