Представляю вам набор функций, которые у меня лежат в отдельном файле utils.js
— это функции, которые я использую чаще всего. Они стараются быть кроссбраузерными и проверены на IE6/7, FF2 и Safari 2 и на боевой, сложной системе, в XHTML документах. Должны, по идее, работать, и на других, но не очень старых версиях браузеров — проверку браузера я использовал только в исключительных случаях. Некоторая часть из них, конечно же, просто нарыта на просторах интернета (где — обычно указано) и заимствована ввиду открытости, а большая часть — сконструирована из многих ресурсов и своих идей (и советов коллег), дабы работать на ура — поскольку часто в разных скриптах не учитываются разные тонкости, которые, тем не менее — при ближайшем рассмотрении — оказываются общностями :) , ну и быть довольно читабельными.
Фукнции разделены тематически:
- ООП —обеспечение (или, вернее сказать — эмуляция) возможности использовать принципы ООП в JavaScript
- Объектная модель JS — использование и расширение встроенных объектов JS
- Определение браузера — чтобы использовать в тех редких случаях, когда это все-таки неизбежно необходимо :)
- Координаты / Позициионирование — вычисление координат и позиционирование объектов — ввиду того, что это часто довольно хитрая штука
- DOM — работа с объектной моделью документа
- AJAX — вспомогательные функции для AJAX — так как это средство часто применимо :)
- Логгинг — иногда он нужен чтобы везде :)
NB! (советы по оптимизации и исправлениям приветствуются)
NB! (если вам не хватает подстветки кода в данной статье и вы используете браузер Firefox — прошу проследовать по этой ссылке за соответствующим плагином, поскольку в бесплатной версии WordPress обеспечить её внутренними средствами нет возможности)
NB! (при написании статьи примеры были взяты из рабочего кода, но в некоторых навскидку изменены названия функций и даже некоторая функциональность. также к коду функций было применено такое форматирование как переносы строк — на данный момент — без проверки последующей работоспособности. как только код будет полностью проверен на работоспособность — этот комментарий будет отсюда удален)
ООП
1. Первый блок — набор из трех функций (две из которых пустые :) ), позволяющих применять (эмулировать?) все три принципа ООП в JavaScript. Из нескольких предложенных на AJAXPath и на AJAXPatterns вариантов я выбрал именно этот ввиду его одновременной понятности (Upd.: на глаз :) — см. комментарии) и быстрой скорости выполнения и немного его видоизменил, так — чтобы отдельно объявленные свойства воспринимались как статические константы.
function Class() { };
Class.prototype.construct = function() { };
Class.extend = function(def) {
var classDef = function() {
if (arguments[0] !== Class) {
this.construct.apply(this, arguments);
}
};
var proto = new this(Class);
var superClass = this.prototype;
for (var n in def) {
var item = def[n];
if (item instanceof Function) item.$ = superClass;
else classDef[n] = item;
proto[n] = item;
}
classDef.prototype = proto;
classDef.extend = this.extend;
return classDef;
};
Полные примеры использования относительно велики, поэтому я их вынесу в следующую статью и проследую далее. Пару простых примеров вы можете наблюдать в пунктах 2, 5 и 15.
2. Следующая функция — простая но изящная — полезна в сочетании с предыдущим набором — она создает функцию-ссылку на метод:
function createMethodReference(object, methodName) {
return function () {
return object[methodName].apply(object, arguments);
};
}
Теперь можно, например, сделать так:
var ScrollingHandler = Class.extend({
construct:
function(elementId) {
this._elementId = elementId;
this.assignListener();
},
assignListener:
function() {
var scrollControlElem =
document.getElementById(this._elementId);
if (scrollControlElem) {
scrollControlElem.onscroll =
createMethodReference(this, "_onElementScroll");
}
},
_onElementScroll:
function(ev) {
ev = ev || window.event;
alert("please stop scrolling,
I've already got an event: " + ev);
}
});
var elmScrollHandler = new ScrollHandler('SomeElmId');
Объект этого класса можно будет ассоциировать с событием скроллинга элемента с указанным ID и совершать что-либо по этому случаю.
Объектная модель JS
3. Нижеприведенная функция клонирует любой объект вместе со всеми его свойствами:
function cloneObj(objToClone) {
var clone = [];
for (i in objToClone) {
clone[i] = objToClone[i];
}
return clone;
}
Использование — простейшее до невозможности:
var clonedObj = cloneObj(objToClone);
4. Конвертер объектов, следующая функция, позволяет удобно использовать всяческие условные (и претендующие ими быть :) ) конструкции вида if (tablet.toLowerCase() in oc(['cialis','mevacor','zocor'])) { alert('I will not!') };
. Код заимствован отсюда.
function oc(a) {
var o = {};
for(var i=0;i<a.length;i++) {
o[a[i]]='';
}
return o;
}
Для примера возьмем ситуацию, когда сначала требуется определить, входит ли объект в какое-либо множество одиночных объектов, а затем — не входит ли он в сочетании с другим объектом в другое множество пар объектов. Допустим, на вечеринку пускают одиночек только с определенными именами, либо пары из списка с позволенными сочетаниями имен:
function isPersonAllowed(maleName, femaleName) {
var pairsAllowed = new Array([ "John", "Yoko" ],
[ "Bill", "Monica" ], [ "Phil", "Sue" ],
[ "Jason", "Harrison" ], [ "Adam", "Eve" ]);
var singlesAllowed = new Array("Michael", "Pete", "John",
"Dave", "Matthew");
return (femaleName
? ([maleName, femaleName] in oc(pairsAllowed))
: (maleName in oc(singlesAllowed)));
}
alert(isPersonAllowed("Jack")); // false
alert(isPersonAllowed("Adam")); // false
alert(isPersonAllowed("John")); // true
alert(isPersonAllowed("Phil","Marlo")); // false
alert(isPersonAllowed("Jason","Harrison")); // true
alert(isPersonAllowed("Martin","Luther")); // false
5. Функция, позволяющая создавать хэш сначала кажется немного излишней: объекты в JavaScript — те же хеши, но вот иногда в качестве имени проперти/ключа требуется задать значение значение переменной и тогда приходит на помощь функия Hash. (да-да, конечно же есть встроенные возможности, но так возможно просто немного очевиднее :) — можете исключить эту функцию из полезных, если хотите :) )
function Hash()
{
this.length = 0;
this.items = new Array();
for (var i = 0; i < arguments.length; i++) {
this.items[arguments[i][0]] = arguments[i][1];
}
}
Доступ к элементам производится засчет свойства items
(кстати, следует, может, в более тяжелой версии добавить keys
:) ?):
var Game = Class.extend({
STG_STOP: 0,
STG_START: 1,
STG_LOADING: 2,
STG_MENU: 3,
STG_PROCESS: 4,
construct:
function() { this._stage = Game.STG_LOADING; },
getStage:
function() { return this._stage; }
});
var stateMap = new Hash(
[ Game.STG_START, "start" ],
[ Game.STG_LOADING, "loading" ],
[ Game.STG_MENU, "menu" ],
[ Game.STG_PROCESS, "process" ],
[ Game.STG_STOP, "stopping" ]);
var someGame = new Game();
alert("You are in "+stateMap.items[someGame.getStage()]+" stage!");
6. Три других функции просто упрощают и/или делают очевиднее некоторые операции: getTime
на 11 символов сокращает доступ к получению текущего времени, getTimeDelta
позволяет найти промежуток в милисекундах между отрезками времени (или указанным моментом и текущим временем, в формате с одним параметром), а последняя функция расширяет свойства объекта Number
для того чтобы при его значении NaN
можно было чуть быстрее получить 0
.
function getTime() {
return new Date().getTime();
}
function getTimeDelta(timeBegin, timeEnd) {
timeEnd = timeEnd || getTime();
return timeEnd - timeBegin;
}
Number.prototype.NaN0=function() { return isNaN(this) ? 0 : this; }
Определение браузера
7. Небольшой объект, поименованные по названиям браузеров свойства которого — суть условия. Этим достигается более читабельное (но не настолько скурпулезное насколько могло бы быть) определение большинства типов браузеров. Этот объект был заимствован мной из проекта, в котором я учавствовал — и как-то прижился, но, думаю, истинные авторы всё-таки где-то в сети, да и код не так уж сложен и громоздок чтобы на него сильно претендовать :). Кроме того, он конечно не идеально надежен (а некоторые говорят что не надежен вообще), но пока на перечисленных браузерах он меня не подвел ни разу :). Если вас не устраивает такое положение дел — вы можете использовать нечто похожее с HowToCreate. И повторюсь: данное определение я стараюсь использовать (как и сказано, например, по ссылке) «только в случае если известен конкретный баг в конкретном браузере и его нужно обойти». Также — несложно пересобрать этот объект в одно длинное условие, для меньшей скорости исполнения (см., опять же, ссылку)
var USER_DATA = {
Browser: {
KHTML: /Konqueror|KHTML/.test(navigator.userAgent) &&
!/Apple/.test(navigator.userAgent),
Safari: /KHTML/.test(navigator.userAgent) &&
/Apple/.test(navigator.userAgent),
Opera: !!window.opera,
MSIE: !!(window.attachEvent && !window.opera),
Gecko: /Gecko/.test(navigator.userAgent) &&
!/Konqueror|KHTML/.test(navigator.userAgent)
},
OS: {
Windows: navigator.platform.indexOf("Win") > -1,
Mac: navigator.platform.indexOf("Mac") > -1,
Linux: navigator.platform.indexOf("Linux") > -1
}
}
Координаты / Позициионирование
8. Набор функций, позволяющих получить координаты элемента на экране пользователя. Если ваш документ статичен относительно окна и не имеет скроллбаров — лучше использовать функцию getPosition
— так будет быстрее. В обратном случае используйте getAlignedPosition
— она учитывает положения скроллбаров. Только обратите внимание: значение top
у элемента может быть орицательным, если элемент верхней частью за пределами окна — для синхронизации с курсором мыши иногда нужно обнулить в этом случае высоту. Основной скрипт позаимствован из одного блога, Aligned-версия — результат поисков по сусекам и совмещения с информацией из двух статей (при обнаружении DOCTYPE
IE входит в свой собственный, несколько непредсказуемый, режим). Также этот метод скомбинирован с получением позиций из исходников руководства по Drag’n’Drop. Обратите внимание: здесь используется функция NaN0
из пункта 6, вам нужно будет добавить ее в скрипт чтобы все работало как надо :) (спасибо, Homer).
var IS_IE = USER_DATA['Browser'].MSIE;
function getPosition(e){
var left = 0;
var top = 0;
while (e.offsetParent) {
left += e.offsetLeft + (e.currentStyle ?
(parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
top += e.offsetTop + (e.currentStyle ?
(parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
e = e.offsetParent;
}
left += e.offsetLeft + (e.currentStyle ?
(parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
top += e.offsetTop + (e.currentStyle ?
(parseInt(e.currentStyle.borderTopWidth)).NaN0(): 0);
return {x:left, y:top};
}
function getAlignedPosition(e) {
var left = 0;
var top = 0;
while (e.offsetParent) {
left += e.offsetLeft + (e.currentStyle ?
(parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
top += e.offsetTop + (e.currentStyle ?
(parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
e = e.offsetParent;
if (e.scrollLeft) {left -= e.scrollLeft; }
if (e.scrollTop) {top -= e.scrollTop; }
}
var docBody = document.documentElement ?
document.documentElement : document.body;
left += e.offsetLeft +
(e.currentStyle ?
(parseInt(e.currentStyle.borderLeftWidth)).NaN0()
: 0) +
(IS_IE ? (parseInt(docBody.scrollLeft)).NaN0() : 0) -
(parseInt(docBody.clientLeft)).NaN0();
top += e.offsetTop +
(e.currentStyle ?
(parseInt(e.currentStyle.borderTopWidth)).NaN0()
: 0) +
(IS_IE ? (parseInt(docBody.scrollTop)).NaN0() : 0) -
(parseInt(docBody.clientTop)).NaN0();
return {x:left, y:top};
}
9. Определить текущие координаты курсора мыши и смещение элемента относительно курсора легко, если использовать соответствующие функции:
function mouseCoords(ev) {
if (ev.pageX || ev.pageY) {
return {x:ev.pageX, y:ev.pageY};
}
var docBody = document.documentElement
? document.documentElement
: document.body;
return {
x: ev.clientX + docBody.scrollLeft - docBody.clientLeft,
y: ev.clientY + docBody.scrollTop - docBody.clientTop
};
}
function getMouseOffset(target, ev, aligned) {
ev = ev || window.event;
if (aligned == null) aligned = false;
var docPos = aligned
? getAlignedPosition(target)
: getPosition(target);
var mousePos = mouseCoords(ev);
return {
x: mousePos.x - docPos.x,
y: mousePos.y - docPos.y
};
}
Последняя функция также может использоваться в двух режимах засчет атрибута aligned
и предназначена для удобного использования в обработчиках событий, например:
function onMouseMove(elm, ev) {
var mouseOffset = getMouseOffset(elm, ev);
console.log("x: %d; y: %d", mouseOffset.x, mouseOffset.y);
}
. . .
<div id="someId" onmousemove="onMouseMove(this, event);
return false;"></div>
NB! (если данные функции (вдруг :) ) не заработают в каком-либо определенном случае — прошу сообщать — хочется добиться максимальной их переносимости)
10. Определение высоты элемента иногда более нелегкая задача чем определение других его параметров, но эти две функции придут на помощь:
function findOffsetHeight(e) {
var res = 0;
while ((res == 0) && e.parentNode) {
e = e.parentNode;
res = e.offsetHeight;
}
return res;
}
function getOffsetHeight(e) {
return this.element.offsetHeight ||
this.element.style.pixelHeight ||
findOffsetHeight(e);
}
DOM
11. Иногда нужно пройти рекурсивно по дереву DOM, начиная с некоторого элемента и выполняя некоторую функцию над каждым из потомков, забираясь в самую глубь. В DOM есть объект TreeWalker
, но он не работает в IE и не всегда удобен/прост в использовании. Функция walkTree
позволяет выполнить некоторую другую функцию над каждым из элементов и позволяет также передать в нее некоторый пакет данных. Функция searchTree
отличается от нее тем, что останавливает проход по дереву при первом удачном результате и возвращает результат в точку вызова:
function walkTree(node, mapFunction, dataPackage) {
if (node == null) return;
mapFunction(node, dataPackage);
for (var i = 0; i < node.childNodes.length; i++) {
walkTree(node.childNodes[i], mapFunction, dataPackage);
}
}
function searchTree(node, searchFunction, dataPackage) {
if (node == null) return;
var funcResult = searchFunction(node, dataPackage);
if (funcResult) return funcResult;
for (var i = 0; i < node.childNodes.length; i++) {
var searchResult = searchTree(node.childNodes[i],
searchFunction, dataPackage);
if (searchResult) return searchResult;
}
}
В примере используются функции setElmAttr
и getElmAttr
, которые будут рассмотрены позже — в пункте 13. По сути они делают то же что и getAttribute
и setAttribute
. Пояснения к используемой функции oc
вы можете посмотреть в пукте 4. В первой части примера корневому элементу атрибут «nodeType» устанавливается в «root», а всем его потомкам — в «child». Во второй части демонстрируется также передача пакета данных — при нахождении первого элемента с атрибутом «class», равным одному из перечисленных в пакете имен, атрибут «isTarget» ему устанавливается в «true».
var rootElement = document.getElementById('rootElm');
setElmAttr(rootElement, "nodeType", "root");
var childNodeFunc = function(node) {
if (node.nodeName && (node.nodeName !== '#text')
&& (node.nodeName !== '#comment')) {
setElmAttr(node, "nodeType", "child");
}
}
walkTree(rootElement, childNodeFunc);
var findTargetNode = function(node, classList) {
if ((node.nodeName && (node.nodeName !== '#text')
&& (node.nodeName !== '#comment')) &&
(getElmAttr(node, "class") in oc(classList))) {
return node;
}
}
var targetNode = searchTree(rootElement, findTargetNode,
['headingClass', 'footerClass', 'tableClass']);
setElmAttr(targetNode, "isTarget", true);
NB! (будьте осторожны с использованием этих функций и постарайтесь избежать их чересчур частого вызова (более раза в секунду) даже на средней ветвистости дереве — они могут пожрать немало ресурсов. или, по крайней мере, вызывайте их в фоне через setTimeout
)
12. Удаление узлов — иногда необходимая задача. Иногда нужно удалить сам узел, а иногда — только его потомков. Функция removeChildrenRecursively
рекурсивно удаляет всех потомков указанного узла, не затрагивая, конечно, его самого. Функция removeElementById
, как и сказано в названии, удалает узел по его id
— при всей простоте задачи способ относительно хитрый:
function removeChildrenRecursively(node)
{
if (!node) return;
while (node.hasChildNodes()) {
removeChildrenRecursively(node.firstChild);
node.removeChild(node.firstChild);
}
}
function removeElementById(nodeId) {
document.getElementById(nodeId).parentNode.removeChild(
document.getElementById(nodeId));
}
13. Казалось бы — элементарная задача работы с атрибутами элемента — иногда наталкивает на абсолютно неожиданные проблемы: например, IE бросает исключение при попытке доступа к атрибутам высоты/ширины элемента table
, а у Safari отличается способ доступа к атрибутам с пространствами имен. Приведенные ниже функции обходят все встреченные мной проблемы без сильного ущерба к скорости выполнения (конечно же, в стандартных случаях лучше использовать встроенные функции):
var IS_SAFARI = USER_DATA['Browser'].Safari;
function getElmAttr(elm, attrName, ns) {
// IE6 fails getAttribute when used on table element
var elmValue = null;
try {
elmValue = (elm.getAttribute
? elm.getAttribute((ns ? (ns + NS_SYMB) : '')
+ attrName) : null);
} catch (e) { return null; }
if (!elmValue && IS_SAFARI) {
elmValue = (elm.getAttributeNS
? elm.getAttributeNS(ns, attrName)
: null);
}
return elmValue;
}
function setElmAttr(elm, attrName, value, ns) {
if (!IS_SAFARI || !ns) {
return (elm.setAttribute
? elm.setAttribute((ns ? (ns + NS_SYMB) : '')
+ attrName, value) : null);
} else {
return (elm.setAttributeNS
? elm.setAttributeNS(ns, attrName, value)
: null);
}
}
function remElmAttr(elm, attrName, ns) {
if (!IS_SAFARI || !ns) {
return (elm.removeAttribute
? elm.removeAttribute((ns ? (ns + NS_SYMB) : '')
+ attrName) : null);
} else {
return (elm.removeAttributeNS
? elm.removeAttributeNS(ns, attrName)
: null);
}
}
Засчет универсальности появляется некоторая неудобочитаемость ввиду того, что необязательный атрибут пространства имен — последний. Решения приветствуются.
AJAX
14. Если вам не нужно ничего большего, чем просто выполнить асинхронный запрос и на основе полученных данных сделать нечто — для вас эта функция. Способ получения объекта XMLHttpRequest
безусловно может быть заменен. Комментарии намеренно оставлены, дабы показать некоторые идеи по расширению:
/* AJAX call */
/* locationURL - URL to use */
/* parameters - url parameters, null if not required
(format: "parameter1=value1¶meter2=value2[...]") */
/* onComplete - listener: function (http_request) or
(http_request, package) */
/* doPost - (optional) specifies if POST (true) or GET (false/null)
request call required
/* package - (optional) some variable or array to tranfer in complete
listener, may be not specified */
function makeRequest(locationURL, parameters, onComplete, doPost,
dataPackage) {
var http_request = false;
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
try {
http_request= new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
http_request = new XMLHttpRequest();
}
}
//if (http_request.overrideMimeType) { // optional
// http_request.overrideMimeType('text/xml');
//}
if (!http_request) {
alert('Cannot create XMLHTTP instance');
return false;
}
completeListener = function() {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
onComplete(http_request, dataPackage)
}
}
};
//var salt = hex_md5(new Date().toString());
http_request.onreadystatechange = completeListener;
if (doPost) {
http_request.open('POST', locationURL, true);
http_request.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
http_request.setRequestHeader("Content-length",
parameters.length);
http_request.setRequestHeader("Connection", "close");
http_request.send(parameters);
} else {
http_request.open('GET', locationURL + (parameters ? ("?" +
parameters) : ""), true);
//http_request.open('GET', './proxy.php?' + parameters +
// "&salt=" + salt, true);
http_request.send(null);
}
}
Пример использования — из одного моего рабочего тестового задания, которое занималось поиском в базе музыки и/или фильмов по введенной в элемент (с id
«searchStr») строке, используя SQL’ный LIKE
:
function gotSearchResults(http_request, dataPackage) {
request_result = http_request.responseText;
var divElement = document.getElementById(dataPackage["divId"]);
divElement.innerHTML = request_result;
}
function insertMusicSearchResults(divId) {
var searchStrElement = document.getElementById("searchStr");
var dataPackage = new Array();
dataPackage["divId"] = divId;
makeRequest("getAlbums.php", "searchStr="
+ searchStrElement.value, gotSearchResults, false,
dataPackage);
}
function insertVideoSearchResults(divId) {
var searchStrElement = document.getElementById("searchStr");
var dataPackage = new Array();
dataPackage["divId"] = divId;
makeRequest("getMovies.php", "searchStr="
+ searchStrElement.value, gotSearchResults, false,
dataPackage);
}
Логгинг
15. Представленная ниже функция для помощи в ведении логов очень проста, добавьте в нужное место в документе элемент <div id="LOG_DIV"></div>
, задайте ему необходимую высоту, и в него будет сбрасываться информация + обеспечиваться ее скроллинг:
function LOG(informerName, text) {
var logElement = document.getElementById('LOG_DIV');
if (logElement) {
logElement.appendChild(document.createTextNode(
informerName + ': ' + text));
logElement.appendChild(document.createElement('br'));
logElement.scrollTop += 50;
}
}
16. В замечательном плагине Firebug для браузера Firefox есть замечательная консоль, в которую с широкими возможностями можно производить логгинг. Однако, если вы отлаживаете параллельно код в других браузерах — обращения к ней могут вызывать ошибки. Для того чтобы не очищать каждый раз код от логов, можно использовать такую заглушку:
var Console = Class.extend({
// the stub class to allow using console when browser have it,
// if not - just pass all calls
construct: function() {},
log: function() { },
info: function() { },
warn: function() { },
error: function() { }
});
if (!window.console) {
console = new Console();
}
Сочетание этого и предыдущего пункта + CSS может вдохновить вас на написание собственной консоли с функциональностью консоли Firebug, но для других браузеров ;). Если вы ее напишете — поделитесь, пожалуйста, со мной :).
Бонус
В качестве бонуса (чтобы не портить приятно отдающее двоичностью число в заголовке :) ) рассажу о проблеме двойного клика — бился над ней не я, а мои коллеги, решение также сетевое — но в некоторой обработке. Проблема состоит в том, что при регистрации события ondblclick
все равно вызывается событие onclick
. Поэтому, если уж очень это событие (неочевидное, стоит заметить, для пользователя сети) необходимо — лучше всего иметь в скриптах следующий код (с необходимым вам количеством миллисекунд и сохраняя, если необходимо, элемент, на котором был совершен клик):
var dblClicked = false;
var dblClickedNode = null;
function dblClick(clickedNode) {
dblClicked = true;
dblClickedNode = clickedNode || dblClickedNode;
}
function releaseDblClick() {
setTimeout('dblClicked=false;', 300);
}
Его использование накладывает относительно сложные условия. Теперь в обработчике ondblclick
нужно вызывать сначала первую функцию, затем — закончив собственно обработку — вторую, а в обработчике onclick
проверять, не совершен ли двойной клик:
<div id="someId" onclick="if (!dblClicked) alert('click');"
ondblick="dblClick(this); alert('dblclick'); releaseDblClick();";></div>
Также, к пункту 1 можно добавить небольшую функцию получения инстанса (на ваше усмотрение вы можете изменить ее так, чтобы она предавала аргументы в конструктор):
function getInstanceOf(className) {
return eval('new ' + className + '()');
}
К пункту 6 подойдет функция паузы (именно паузы, а не выполнения в отдельном поптоке, как делает setTimeout
):
function pause(millis)
{
var time = new Date();
var curTime = null;
do { curTime = new Date(); }
while (curTime - time < millis);
}
Заключение
Ну вот — кажется, пока всё. Статья — в состоянии готовности к исправлениям (если понадобятся :) ), можно переходить к следующим :). В следующей статье я намереваюсь рассказать поподробнее про ООП в JavaScript и привести в пример пару простых, но полезных классов. Надеюсь, эта статья вам помогла и хоть немного сократила имеющие потенциальную возможность быть потраченными на решение всяких причуд браузеров рабочие человекочасы.
Скажите, а в чём тайный смысл передачи аргумента:
var proto = new this(Class);
И соответственно последующей проверки:
if (arguments[0] !== Class) {…
Это в первом примере. Просто интересно.
Продажа и срочная доставка цветов и букетов, интернет доставка БЕСПЛАТНАЯ ДОСТАВКА ЦВЕТОВ ПО МОСКВЕ! Любой букет цветов на заказ — ЗВОНИТЕ! B 2002 году в Пензе был открыт наш первый салон цветов и подарков! Начинали с букетов и композиций из живых цветов, подарков и сувениров. Особо интересны осенью деревья и кустарники с красивыми плодами. К потолку балкона можно прикрепить подвесные кашпо, а также плетеные корзинки.
Хм, если я стараюсь разобрать в сонном состоянии конструкцию первого решения, то вижу примерно такую картину (днем она обычно видится очевиднее :) ):
(Upd.: мнение в этом абзаце неправильное, см. инфу ниже)
classDef
— собственно функция, которая вызывается тогда, когда мы делаем, например,var smth = new BlahClass()
(поскольку именно ей мы на самом деле присваиваем значение переменной, совершаяvar BlahClass = Class.extend({...
) тогда ее нулевым аргументом, ввиду этой всей архитектуры, будет тот самыйBlahClass
. Проверкаif (arguments[0] !== Class) {…
показывает что вызывает ее отнаследованный класс, а не корневойClass
(у которого, ввиду архитектуры, пустой конструктор :) ) и поэтому можно вызывать конструктор переданного класса.Смысл же строчки
var proto = new this(Class);
по моему скроному мнению кроется в том, что прототипом функцииclassDef
должна в будущем стать эта же функцияextend
, выполненная над функциейClass
.Надеюсь, объяснил :)
classDef вызывается 2 раза (если не принимать во внимание самое начало, когда работает Class и на выхлопе появляется какой-нибудь SubClass), один вызов при создании нового объекта-экземпляра, другой вызов при расширении, когда нужно создать proto. Насколько я понял, чтобы при создании этого proto не вызывать this.construct внутри конструктора туда передаётся типа некий флажок (Class), сигнализируя, что это строится proto, не надо ничего делать.
Вот эта вот композиция с флажком в виде ссылки на функцию выглядит странновато, почему внутри функции classDef просто не проверить приход аргументов и только при их наличии запускать this.construct (судя по всему это метод, обвешиваюший объект полями). Соответственно пишем proto = new this; безо всяких аргументов… Или там всё-таки есть другой смысл?
Есть очень легкий способ выяснить всю подоплеку однозначно — дебаг в Firebug’e.
Практика показала (Upd.: на самом деле не показала, поскольку я действительно забыл про инстансы, позор дважды на мою голову) и снова, что все-таки
classDef
выполняется один раз и условиеargument[0] !== Class
является истинным только в том случае, если у класса банально нету констуктора (то есть ночной мой тезис был, к сожалению, неверен :) ). Тайный смысл вызоваthis(Class)
открывается, если вспомнить чтоextend
— это «статический метод» .Нет чего-то тайный смысл вызова не открывается, во всех случаях Class передаётся впустую в качестве флага. Чтобы не было разночтений ниже ссылка, чтоб в профайлер удобно было засунуть:
http://zeroglif.googlepages.com/class_create.html
Я код не менял, он такой же как на AJAXPatterns, только «экземпляры» создаются. Итого видно, что при каждом экстенде создаётся proto (это первый вызов), потом при создании объекта второй вызов той же функции. Всего 2 вызова на создание «класса» плюс «экземпляра». Кроме самого первого «класса», для которого proto делает Class…
Хорошо, Вы всерьез заинтересовали меня этим вопросом — я, видимо, поначалу, не уделил ему должного внимания, основываясь на доверии к авторам решения, и посему по приходу домой с работы, я разберусь с происходящим досконально до самой глубинной материи.
Upd.: Коллега подсказал, что, возможно, сделано сие для эмуляции вызова конструктора (которых в JavaScript, в том смысле как в ООП-языках программирования — нет) по всей иерархии классов — и число вызовов
classDef
тогда обретает новый смысл (думаю, если посувать где возникают вопросыconsole.log(...)
— проблему будет легче осмотреть сверху).TODO: интересующимся следует почитать здесь :).
>>TODO: интересующимся следует почитать здесь :).
Или вот тут по ссылкам, чтоб накрыло по-настоящему:
http://forum.vingrad.ru/index.php?showtopic=120066&view=findpost&p=1215304
Для того чтоыбы заработала функция getPosition из 8 решения впереди нее следует добавить к
объекут Number следующий метод:
Number.prototype.NaN0 = function() { if (isNaN(this)) return 0; else return this; }
Антон, подборка кода действительно полезная, но хотелось бы не тратить время на то что бы
заставить его работать. Понятно, что все проверить нельзя, но за чем тогда постить то, чем сам
не пользовался? Или приводи точные ссылки — откуда что взято. Пожалуйста.
Возможно, Денис, вы не заметили:
а) но в самом верху стоит пояснение о том, что это все — одна библиотека и она используется постоянно в моей работе — и, возможно, вы не поверите, но я ей действительно пользуюсь; метод
NaN0
описан в пункте 6, откуда вы не поленились его скопировать;б) ссылки на то, откуда что взято — приведены. это такие подчеркнутые синим слова. другое дело что эта функция претерпела много исправлений и не все источники я упомянул — это я исправлю.
в) также вверху стоит предупреждение что не весь код полностью проверен на работоспособность по причине того, что он вставлялся из рабочих исходников, но по кускам и с переносами строк. Моя вина что я так и не сделал полную и аккуратную проверку. Я бы сам хотел чтобы мне предоставляли тарелки с голубыми каемочками, и хотел бы предоставить их и читателям — но не всегда так получается, верно?
Действительно, я должен был упомянуть что читателю нужно взглянуть чуть выше — и это единственное место где я забыл это сделать — я исправлю и это. Но разве так трудно программисту, который не поленился скопировать код и написать вышестоящий комментарий, нажать Ctrl+F на той же странице ? Обвинения в прочем считаю не обоснованными.
В любом случае, благодаря вам статья станет лучше. Спасибо. Извините, если что не так.
Добрый день, не могу понять, использую Ваши getPosition и mouseCoords, но при клике по объекту положение мыши по оси Y получается меньше чем Y элемента, по которому произведен клик. Естественно offset получается отрицательный, из-за чего так может происходить?
Здравствуйте,
Возможно у какого-либо объекта в DOM offsetParent не определен, либо offsetTop неверен или отсутствует, возможно на это влияет скроллинг, если он есть. Не могли бы вы, если возможно, привести код.
Отличная подборка спасибо, натолкнула на мысли по усовершенствованию своего фреймворка….
А ссылку на всю сборку utils.js можно? Хочу погонять на реальных задачах.
Добавил бы сюда еще возможность перехватывать и отслеживать ошибки в JS! Я например отлавливаю их и через Ajax + PHP сохраняю в базу данных. Потом всегда буду знать, какие ошибки случаются у моих посетителей и как их исправить.
Ae4IzG http://www.DWi1XMPP0jh3l9pDiAZhyZdXicPGCzu9.com
An accountancy practice http://www.zoji.com/1230675 lola teen non nude I would tap that tight little ass in a minute. Cute with that lingerie on.Nice pussy lips on her too.
I never went to university sexy young lolita schoolgirls This is just beautiful from begining to end
A financial advisor http://www.zoji.com/1230683 lolicon little lolita nude What do you mean? He just laid there with his rod in the air . . . He didn’t even play wit the clit while he was shagging her
Hello good day pretty little lolita nudes very lovely
Could I ask who’s calling? http://community.parents.com/asumouooi/blog/2013/04/04/lolita_kingdom_nude_pics little nude lolita preeteens He has not many seeds to give, but his body hair is fantastic and his glans are beyond words :)
I’d like to apply for this job lolita young picture galleries she is the hottest shemale ever! i so wish i was there when she’s spreading her cheeks, it is heaven!! by the way, her name is bianca friere, for the people who were wondering
We need someone with qualifications child elwebb bbs lolita lookat that pussy!!!
Have you got any qualifications? http://www.mycraftingplace.com/lsmagazinexl lolitas young best bbs to much blow jobing…
маленькое ускорение:
for(var i=0;i<a.length;i++)
заменить на
for(var i=0, var len=a.length;i<len;i++)
I was born in Australia but grew up in England abilify price 2mg 4.5.3 Bulk / Merged Prescription Forms
What’s the interest rate on this account? http://connect.masslive.com/user/kehipunia/index.html sites lollitas non nudes Awesome dick. Too bad he didn’t want to show his face. Would love to see that dick walk by at the gym in a pair of sweats.
I really like swimming http://connect.masslive.com/user/jynosocuqy/index.html nude preteen lolita collection Ariel X manages to massage bree olsen into an orgasm is that enuff nuuh she got massage EVRY BLONDE INTO AN ORGSASM shes hot
What are the hours of work? http://connect.masslive.com/user/enopyquniki/index.html preteen bbs sexy lolitas I’m curious I remember watching a video on couple who did threesomes FFM and they had a rule where they(the couple) would do everything with the other female but intercourse, the female person of the couple wasn’t cool with that, are you that way ? I mean you don’t share completely everything ? I hope I made sense !
How much notice do you have to give? http://connect.masslive.com/user/jynosocuqy/index.html nude preteen lolita collection lmao PimpMicPimp, i was so distracted by how hot so was i didn’t notice the room, but thanks for pointing that out.
A packet of envelopes cheap marlboro ultra lights 100’s will be considered eligible for Medicaid reimbursable
What do you want to do when you’ve finished? промокод kidmart
Do you like it here? how to find cheating husband Students are expected to review topic objectives, complete all reading assignments, and, if
What do you do for a living? buy anafranil Border’s pace attack of Merv Hughes, Geoff Lawson and Terry Alderman were the Johnson, Siddle and Harris of their day, with big Merv even shading the battle of the moustaches. Even the composition of the batting was similar with Border, the captain, being the dominant player who had long carried his team, as Clarke has done despite his bad back. They even had a stocky, aggressive opener like David Warner — David Boon setting the tone as well as the record for cans of lager (52) drunk on the Sydney-London flight.
I’d like to transfer some money to this account buy famciclovir The second leg against Houston was a start. Zusi was energetic and ubiquitous in the midfield — supporting team mates, harrying, running at defenders and on a couple of occasions shooting just over (still not on target mind you) after decisive forward runs.
Free medical insurance http://buycytotec.net/ buy cytotec online
(12) Tierney WM, Rotich JK, Smith FE, Bii J, Einterz RM, Hannan TJ. Crossing the
Have you got a current driving licence? benicar alternatives To help explain the theme, I need to put the plot in the context of Park’s work. Revenge is central to his films: He understands the Western obsession with an eye for an eye â or an eye, nose and teeth for an eye.
Which team do you support? benicar hct 40 Now, a detailed analysis of the chemistry and geology of an area of Mars called Yellowknife Bay, described in a series of papers in the journal Science Monday, confirms that around 3.6 billion years ago, the Red Planet had conditions well suited for life for a period of at least hundreds of years to tens of thousands of years. Details were presented at the American Geophysical Union meeting in San Francisco Monday.
Three years benicar 20 mg I'm infuriated by these blanket statements regarding life expectancy! Firstly, it changes according to where you live in the country and secondly there's no thought as to how people earn their living; so somebody who has spent their lives sat at a desk retires at the same time as somebody in heavy industry or that has spent their lives carrying bricks up ladders!
i’m fine good work how much does celexa cost «Even under the most optimistic scenario the IFS considered, in 2021-22 an independent Scotland could have to find permanent tax increases or spending cuts that would be equivalent to £3bn in today's terms,» he said.
How much notice do you have to give? buy clomid online from mexico Having become aware last year of the presence in Britain of Brar and his wife, the group travelled to London and carried out reconnaissance of the area where they were staying, the police statement said.
Very Good Site desyrel oral The storm dumped as much as 2 feet of snow in parts of Minnesota, forcing school closures and temporary power outages and delighting skiers who were hitting the slopes despite temperatures in the single digits Thursday.
Could you please repeat that? how to buy doxycycline Protest leader Suthep Thaugsuban repeated a call forYingluck and her ministers to resign within three days or facerenewed anti-government demonstrations. No rallies have beenplanned in Bangkok today. The dollarâs 14-day relative strengthindex versus the baht dropped to 57 from as high as 81 lastweek. A level above 70 suggests to some traders the SoutheastAsian currency was oversold and poised to change direction.
I can’t get a dialling tone order amitriptyline no prescription Unlike large distributors, Black Pearl only roasts to order for the numerous cafés and restaurants they supply. They also make custom blends, and he can guide you to a bag of beans that will suit your tastes, be it low acidity, or a smokier finish.
Have you got any qualifications? purchase desyrel online Not realizing he was holding an improvised explosive device, Cannon left the bear and put the cylindrical item in his car for the 20-minute drive back to Shelby. He drove to his cousinâs home, where he examined what he had found more closely in the light.
Is there ? permethrin spray “I once sold a house in Fulham that had a pond in the back garden with six koi carp. The new owner wanted to destroy the pond and we couldn’t find a pet shop to take the fish, so I auctioned them for Great Ormond Street Charity, making just under £200. We then spent the best part of two hours, at 9pm one evening fishing them out of the pond in the dark.”
Punk not dead endep 10 Overall, including both winners and losers but still omitting Oregon, competing for the BCS title resulted in an average 16% increase in revenue from the season before through the season after the championship game. So it seems all but assured that, even if conference distributions are unaffected, a BCS championship bid for FSU would mean an immediate and significant boost in football revenue, which was $43 million in 2012-13.
I’ve been cut off hydrochlorothiazide online PISA 2012 also reaffirms the appeal by millions of teachers worldwide: pay us better. While paying teachers well is only part of the story, higher salaries can help countries to attract more young people to choose teaching as their lifelong career. PISA results show that more successful countries pay more to their teachers and give them higher status in society.
Could you ask her to call me? permethrin cream The Highland Park Republican checked into the hospital Saturday after experiencing stomach pains. After conducting tests, including an MRI, doctors determined Kirk had gallstones, hard deposits that can form in the gallbladder. According to the Mayo Clinic, gallstones are common and occur in about 10 to 15 percent of adults in the United States.
Free medical insurance can u buy flagyl over counter Most breast cancer tumors are estrogen-receptor positive, fueled by the hormone estrogen. About 20 percent are HER2-positive, meaning a protein called HER2 is prevalent. A third type is driven by the hormone progesterone. All of these have potentially effective treatment options even after recurrence.
I’d like , please imitrex chest pain Ahead of the Autumn Statement, Mr Osborne said: «Science is a personal priority of mine. This Government will continue to prioritise the long-term investments that are needed to compete in the global race.»
Do you know what extension he’s on? 600 ibuprofen The short supply of engineers frequently means this formal process isn’t performed, or at least not adequately. Instead, vulnerabilities are patched as they become apparent (hence Microsoft’s twice monthly «Patch Tuesday»), often after the damage is done.
Sorry, you must have the wrong number what is motrin Squeezed between two sets of back-to-backs against the four best teams out West, all a part of a challenging five-game road trip, the Pacers were in Utah Wednesday night. The Jazz are at the bottom of the Western Conference standings, but had recent momentum from winning three of their previous four games.
Best Site Good Work neurontin 600 mg high This week in streaming video, we’ve got a a sci-fi action film with a message, a sequel to a popular animated film, an auteur’s biopic of a famous martial artist, and an action sequel, as well as a couple of worthy TV shows to watch. Read on to see what’s available to watch right now.
Could you please repeat that? where to order nexium A photo of a female protester kissing an Italian riot policeman hailed as an emblematic image of peace in Italy, has not gone down well with a police union, which wants the protester prosecuted for sexual violence.
I’m a trainee nizoral for acne «Often the church is one of the best record keepers in the community,» Hardy says. «So to understand where people are living, what they have lost, which people have left after Typhoon Haiyan hit this area, when they will be coming back, the church can often be one of our best resources for that information.»
Hello good day paxil xanax together Those loans were secured on favourable terms against future income from union affiliation fees, the newspaper said â ties which Mr Miliband has said he is reconsidering in the wake of alleged union interference in the selection of a Falkirk Labour candidate.
Sorry, I’m busy at the moment prozac zoloft paxil called «It comes as a big plate of lettuce â which is questionable in a caprese, which doesn’t typically have lettuce at all. The tomatoes â and it’s supposed to be tomatoes, cheese, basil â they were pushed off to the side, almost as a garnish. And the tomatoes were hard and unripe.»
I’m doing a masters in law buy ketoconazole «So I can somehow feel that I’ve been productive in my entertainment today,» Hill said with a laugh. «Which in of itself is ridiculous because one of the reasons we adopt entertainment as part of our lifestyle is to avoid that constant American rat race of being X-percentage productive and efficient in a given day.»
I was born in Australia but grew up in England buy zithromax overnight I meet Tom Evans at a restaurant in London. He doesn’t live in the capital. He moved out years ago to a large house in Lewes – large enough for him, his American wife, Liz, and his two children, Peter and Amanda, now aged seven and five.
I can’t get a dialling tone average cost of acyclovir Here is an occasion for all gardeners to help defend it — find out the name of your member of the European Parliament (MEP) and write to them by the end of November. A future world of Eurocrat-approved garden plants is a bleak prospect.
I’ve got a full-time job cipralex withdrawal But Texas started 1-2 to rekindle dissatisfaction that would fester all season, particularly after revelations that in January, several members of the school's board of regents and a prominent donor were involved in efforts to lure Alabama coach Nick Saban to the Longhorns.
An envelope avapro 10 mg âMoreover significant health benefits were even seen among participants who became physically active in later life. This study supports public health initiatives designed to engage older adults in physical activity, even those who are of advanced age.â
Could I order a new chequebook, please? benicar coupons In addition to the NROL-39 payload, the Government Experimental Multi-Satellite (GEMSat), consisting of 12 CubeSats, took advantage of the Atlas V launch vehicle ride share capabilities and were deployed following completion of the primary mission. The NRO and ULA partnered to develop an Aft Bulkhead Carrier (ABC) on the Centaur upper stage, which is a platform for accommodating auxiliary payloads aboard Atlas V missions.
Thanks funny site buy non prescription clomid âApproximately 20,000 credit cards may have been compromised via this Stardust variation and evidence has been sent to the card associations to determine the points of compromise,â said Dan Clements, the president of IntelCrawler, via email.
What do you want to do when you’ve finished? cleocin tablets Powered by Tokyo’s aggressive fiscal and monetary stimulus, the Nikkei has rallied 51 percent this year. If the gains were to hold for the rest of this year, it would be the best yearly rise since 1972.
Could you tell me the number for ? cleocin antibiotic Upon hearing the news about her sister’s deafness, Kourtney was immediately filled with gratitude to the Lord as she felt he had prepared her for this. As of recently, Kourtney has felt the need to learn sign language. She purchased “Signing Time” videos and learned all of the children signs so she could communicate with her baby. Little did she know it will also serve to communicate with her adopted sister. Kourtney has since begun attending weekly sign language classes.
I’m only getting an answering machine order combivent online Initially, Oracle promised it could get the job done. But by mid-May, the head of Cover Oregon, Rocky King, had written the company, pleading for «a simple calendar schedule … to ascertain whether or not we will be able to deliver» a working exchange by Oct. 1.
I never went to university clindamycin phosphate gel Tomas Plekanec also scored for Montreal (18-9-3), which jumped a point ahead of Boston (18-8-2) into first place in the Atlantic Division — although the Bruins have two games in hand. The Canadiens are 8-0-1 in their last nine.
I’d like to pay this cheque in, please amitriptyline price comparison Aficionados who snap up new technology as soon as it becomes available are already hotly anticipating the device. But to reach a broader market, Google has to clear several hurdles, among them taming the device’s geeky image and adapting it for the more than 110 million Americans who are already wearing glasses to correct their vision.
My battery’s about to run out how to stop taking effexor xr 75 mg VILNIUS, LithuaniaâEuropean leaders acknowledged Thursday there would be no last-ditch deal with Ukraine on a sweeping trade and political deal at this week’s two-day Vilnius summit despite a last-gasp meeting between Ukraine’s president and the European Union’s top two officials.
Have you read any good books lately? elavil 25 mg amitriptyline Two-thirds of the turkeys on the unidentified farm in East Anglia were infected and hundreds of the birds have already been sold to local shops and through farm gate sales. The farmer is co-operating with the authorities.
What do you study? desyrel with zoloft «This is where I hoped we’d get to when I joined,» Sissoko said. «Last season was a really difficult time for the club but when we arrived we had a mission to make sure we got the points on the board to stay up. It was hard but we did it.
Which year are you in? effexor xr 75 mg weight gain However, Thuli Madonsela, the country’s public protector, reportedly found that Mr Zuma derived “substantial personal benefit” from so-called “security upgrades” to the compound in Nkandla in eastern KwaZulu-Natal province, many of which had nothing to do with security.
I can’t stand football motilium 10 Sony Corp. (6758) will cut $250 million incosts at its entertainment units over two years, part of ChiefExecutive Officer Kazuo Hiraiâs plan to boost profit and keepfull ownership of the movie, TV and music businesses.
I live in London how much does strattera cost without insurance Zion Lutheran 83, Jupiter Christian 29: K. Battle 28, B. Battle 21, T. Battle 15. JC: Paulis 11. Rebounds: Litt 8. Steals: B. Battle 6. Assists : K. Battle 7. Three-pointers: B. Battle 4, K. Battle 4, T. Battle 1. ZL 6-0.
Have you read any good books lately? synthroid 0.2 mg Thereâs no interior point of view offered for driving, but you can see into the cabin through the windows, where the new design is recreated perfectly. It even features the auxiliary gauges on the center stack that come with the Mustangâs Performance Pack, a commemorative 50th anniversary dashboard plaque on the dash and the 8-inch MyFord Touch screen with map display.
I want to report a purchase imipramine online Walker, who starred in all but one of the six «Fast & Furious» blockbuster films that glorified fast cars and dangerous driving, was killed when the Porsche smashed into a light pole and tree then caught fire on Saturday afternoon, authorities said. The seventh installment of the movie series was on a break from shooting for the Thanksgiving holiday.
We work together vermox canada «I’ll give them credit for staying in the fight and having an opportunity to win the game,» Wizards coach Randy Wittman said. «But when you don’t play for 42 minutes, you’ve got to play perfect basketball. … I just don’t think we were ready to play.»
Could you ask him to call me? wellbutrin xl discount card The ideas are likely to be central to Mr Cameronâs efforts to renegotiate Britainâs relationship with the EU. Liberal Democrat sources made clear Ms May was not acting on behalf of the Coalition but in a Tory Party role.
Looking for a job where can i buy acyclovir in bulk The email was sent six days after the incident, on 25 September, when the matter was already public. The correspondent claimed to have witnessed and filmed the incident and said that the word «pleb» was not used.
this post is fantastic where to buy acyclovir ointment The pair, who left London in August, have tackled deserts, negotiated jungles and survived encounters with elephants as well as an accident in Malaysia when a truck ploughed into the back of their tuk-tuk.
Could I order a new chequebook, please? zoloft 75 mg tabs Two vast and flat platforms sandwich a deep-set array of glass walls and concrete blocks with a broad verandah and upper balcony circling around. The whole is then raised up on stilts just high enough above the flood plain to catch the breezes off Biscayne Bay and keep the parking underneath and out of sight. Suspended vertically from the roof like Seminole totems to the jungle gods, dozens of 50-foot logsâactually watering pipes wrapped in felt and covered in local and South American flora by French landscape consultant Patrick Blancâlend the verandah a primordial lushness. The greenery also helps to modulate an outdoor space that might otherwise have felt too monumental (an issue with the barren overhang at the Parrish museum).
Do you know the address? buy acyclovir cream for genital herpes The earlier openings and sales were met with some resistance. Some workers’ rights groups had planned protests on both Thanksgiving and Black Friday because they opposed having retail employees miss family meals at home. Some shoppers had said they would not venture out on Thanksgiving because they believe it’s a sacred holiday meant to spend with family and friends.