Продвинутые конструкции в Javascript
Я нашел один интересный проект на 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 ответов
Работая снаружи, первая большая концепция здесь - анонимные функции.
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.
Книга Дугласа Крокфорда " JavaScript: хорошие части" - отличное место для того, чтобы оценить мощь JavaScript, одновременно отвлекая вас от уродливых (или совершенно опасных) частей. На его сайте также есть коллекция интересных статей о языке. Я рекомендую оба.
Может быть, некоторые из этих ссылок помогут вам:
https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Details_of_the_Object_Model, https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript, https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Objects, https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited,
Я могу сослаться на некоторые ссылки
Могу ли я назвать функцию JavaScript и выполнить ее немедленно?
http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx
Я надеюсь, что вы можете учиться с ними
Я нахожу блоги Дугласа Крокфорда ( http://www.crockford.com/), Джона Резига ( http://ejohn.org/blog/) полезными для промежуточных и продвинутых концепций. Просмотр кода других людей (как и то, что вы делаете) также может быть полезным. В конце концов, хотя ничто не сравнится с проверкой концепции, и для этого надежная консоль Firebug по-прежнему является лучшей.