js-core reloaded

Octane, 08.01.2009

js-core logotypeИтак, прошло уже много времени с момента, когда я (Коробкин Дмитрий) начал заниматься разработкой своего JavaScript фреймворка. Целью было создать продукт, который бы занял свое место среди небольших и быстрых библиотек, позволяющих более удобно производить манипуляции с DOM, легко организовывать AJAX-запросы, а главное в какой-то степени избавить программиста от проблемы кросс-браузерности.

Теперь, пройдя множество исправлений, дополнений и модификаций, js-core вполне может использоваться в проектах любой сложности, обеспечивая достойный уровень производительности. В версии 2.7 структура фреймворка была полностью изменена, он не будет вызывать конфликты с другими скриптами, из-за внедрения пользовательских методов в прототипы встроенных объектов JavaScript. В глобальное пространство имен помещается только один объект с ссылками core и $ на него. Появилась возможность работы со списками узлов.

Содержание

Функция $(…) — получение элемента по идентификатору, кэширование

Допустим, у нас есть следующий XHTML-код:

<div id="container"></div>

Чтобы получить ссылку на узел <div&gt; с идентификатором container, в JavaScript предусмотрен метод getElementById(…) объекта document:

var node = document.getElementById('container');

Существует очень распространенная функция, сокращающая эту запись:

function $(id) {
    return document.getElementById(id);
}

Или более сложный вариант:

function $(arg) {
    return typeof arg == 'string' ? document.getElementById(arg) : arg;
}

В таком виде функция $(…) просто сокращает запись метода getElementById(…), предавая прямую ссылку на узел.

В js-core функции core(…) и $(…) эквивалентны, и возвращают новую копию объекта core, содержащую ссылку на указанный узел. Таким образом, через прототип объекта core для этого узла становится доступен набор методов, позволяющих производить манипуляции с DOM, добавлять обработчики событий и изменять стили элемента.

Выполним следующий код, с использованием фреймворка:

var obj = $('container')

// или
var obj = core('container')

// или
var obj = new $('container')

// или
var obj = new core('container')

Все эти варианты абсолютно равнозначны, только, последние 2 теоретически должны выполнится быстрее, т. к. первые просто рекурсивно вызывают функцию core в конструкторе new. В результате переменная obj будет ссылкой на объект следующего вида:

{node: HTMLDivElement}

Такой объект можно бы было получить, например, такми образом:

var obj = {node: document.getElementById('container')}

Но у созданного при помощи функции core(…) или $(…), входящих в состав js-core, объекта есть одно важное отличие — наличие специальных методов в прототипе, доступ к которым осуществляется так же, как и к любым другим методам объектов в JavaScript:

$('container').hide()

// или
$('container')['hide']()

Забегая вперед, скажу, что метод hide(…) просто скрывает указанный элемент.

Чтобы получить прямую ссылку на DOM-узел, достаточно написать:

var node = $('container').node

Так же в любой момент можно беспрепятственно воспользоваться этой ссылкой в уже созданном, функциями core(…) или $(…), объекте:

var obj = $('container')
var node = obj.node

Если отправить в функцию core(…) или $(…) не строку, содержащую имя идентификатора узла, а ссылку на узел, то она автоматически будет запомнена в том же атрибуте node:

var obj = $(document.getElementById('container'))
alert(obj.node.id) // выдаст сообщение "container"

Все ссылки на элементы, полученные по идентификатору, помещаются в кэш. Кэш очищается каждый раз, когда выполняется удаление DOM-узлов или изменение идентификатора средствами фреймворка. Если вы производили какие-либо манипуляции с DOM и у вас возникли проблемы из-за наличия в кэше ссылок на удаленные узлы, достаточно просто инициализировать кэш ссылкой на новый объект:

$.cache = {}

Или выполнить функцию $.clear(…), передав в нее в качестве аргумента, ссылку на изменяемый узел:

$.clear(document.getElementById('container'))

Если вы уже используете функцию $(…), то js-core не заменит её, если она будет создана до подключения фреймворка. В этом случае можно использовать функцию core(…) или заключить код, использующий js-core в функцию-обертку:

(function($) {
    // Здесь $(…) — функция фреймворка "js-core"
})(core);

Цепочки — последовательный вызов методов

JavaScript позволяет реализовать последовательный вызов методов, называемый «цепочками вызовов». В js-core активно используется эта возможно, что позволяет в некоторых случаях обойтись без дополнительных переменных. Рассмотрим это на простом примере, добавим элементу с идентификатором container CSS-класс highlight и какой-то текст:

$('container').addClass('highlight').text('Пример')

// или
$('container').text('Пример').addClass('highlight')

В какой последовательности вызывать методы, работающие с одним и тем же узлом, в данном случае, не имеет значения.

В результате получим:

<div id="container" class="highlight">Пример</div>

Цепочку можно продолжать, вызывая доступные методы.

Если все-таки необходимо запомнить ссылку на объект в переменную, то можно сделать это несколькими способами:

var obj = $('container')
obj.addClass('highlight').text('Пример')

// или
var obj = $('container').text('Пример').addClass('highlight')

Второй вариант возможен ввиду того, что методы возвращают объект, созданный на первом звене цепочки вызовов. Но, так происходит не всегда, в фреймворке есть функции, которые могут либо обрывать цепочку, возвращая какое-то значение, либо продолжать цепочку, но работая уже с новым объектом.

Допустим, у нас есть следующий XHTML-код:

<div id="container">Пример</div>

Добавим элементу с идентификатором container CSS-класс highlight и сохраним в переменную содержащийся в нем текст:

var text = $('container').addClass('highlight').text()
alert(text) // выдаст сообщение "Пример"

Вызванный метод text(), без параметров, обрывает цепочку и возвращает innerText текущего узла.

Другой тип функций передает в цепочке новый объект, содержащий, например, ссылку на добавленный элемент:

var obj = $('container').addClass('highlight').append('span')

В результате в переменной obj будет находиться ссылка на HTMLSpanElement, а не HTMLDivElement, таким образом, можно продолжить цепочку:

var obj = $('container').addClass('highlight')
                        .append('span').text('Добавленный текст')

Переменная obj все так же будет содержать ссылку на HTMLSpanElement, так как метод text вернет предыдущий в цепочке объект, созданный функцией append(…).

XHTML-код приобретет следующий вид:

<div id="container" class="highlight">
    Пример
    <span>Добавленный текст</span>
</div>

Текущий элемент, контекст вызова

Из предыдущего примера видно, что элемент, с которым идет работа в цепочке вызовов, может изменяться. Соответственно изменяется и контекст вызова функций this, происходит это следующим образом:

$('container')      // this → HTMLDivElement
.append('fieldset') // this → HTMLFieldsetElement
.append('p')        // this → HTMLParagraphElement
.prepend('span')    // this → HTMLSpanElement
.text('Пример')     // this → HTMLSpanElement

Получим XHTML-код:

<div id="container">
    <fieldset>
        <p>
            <span>Пример</span>
        </p>
    </fieldset>
</div>

Таким образом, можно выполнить код последовательно, для каждого элемента, не запоминая ссылку на него в переменную:

$('container').exist(function() {
    // this → HTMLDivElement
}).append('fieldset').exist(function() {
    // this → HTMLFieldsetElement
}).append('p').exist(function() {
    // this → HTMLParagraphElement
}).prepend('span').exist(function() {
    // this → HTMLSpanElement
}).text('Пример') // this → HTMLSpanElement

Метод exist(…) проверяет наличие элемента и запускает callback-функйцию, которая вызывается в контексте текущего узла.

Обработка событий

Кросс-браузерная обработка событий, наверное, одна из самых сложных частей фреймворка, как для понимания, так и в плане реализации.

Добавление/удаление обработчиков событий

В Internet Explorer, в отличие от других браузеров, выполняемые по событию функции, добавленные методом attachEvent(…), не получают в качестве первого аргумента объект-событие и не вызываются в контексте элемента, к событию которого «привязаны». Чтобы частично решить эту проблему в js-core все анонимные функции, добавляемые в обработчик события какого-либо элемента, автоматически вызываются в контексте этого элемента, а для получения объекта-событие предусмотрены специальные методы, о которых позже.

Добавим обработчик события click для узла с идентификатором container:

$('container').bind('click', function() {
    // this → HTMLDivElement
})

Для анонимной функции, переданной в метод bind(…), в Internet Explorer будет автоматически добавлена «обертка», вызывающая эту функцию в контексте узла с идентификатором container. Чтобы иметь возможность удалить функцию из обработчика события, т. е. выполнить метод removeEventListener(…)/detachEvent(…), для именованных функций такая обертка не добавляется, но предусмотрен специальный метод context(…), который можно использовать следующим образом:

function test() {
    // this → HTMLDivElement
}
var obj = $('container')
var func = $.context(test, obj.node)
obj.bind('click', func) // добавляем обработчик события
…
obj.unbind('click', func) // удаляем обработчик события

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

var func, obj = $('container');
obj.bind('click', (func = $.context(function() {
    // this → HTMLDivElement
}, obj.node))) // добавляем обработчик события
…
obj.unbind('click', func) // удаляем обработчик события

Работа с объектом-событие

Для работы с объектом-событие предусмотрен метод $.event(…), который возвращает, так же как и в случае с функцией $(…), специальную обертку, содержащую ссылку на этот объект, через прототип которой доступны методы для работы с событием.

Получить объект-событие можно несколькими способами:

$('container').bind('mousedown', function(eventObject) {
    eventObject = eventObject || window.event
    $.event(eventObject)
})

// или
$('container').bind('mousedown', function(eventObject) {
    var eventObject = arguments[0] || window.event
    $.event(eventObject)
})

// или
$('container').bind('mousedown', function(eventObject) {
    $.event(eventObject)
})

// или
$('container').bind('mousedown', function() {
    $.event(arguments[0])
})

Все эти варианты успешно сработают. Далее в примерах будем использовать последний вариант.

События мыши
$('container').bind('mousedown', function() {
    var eventObj = $.event(arguments[0]) // обертка для объекта-событие
    eventObj.object // ссылка на объект-событие
    eventObj.mouseButton() // выдаст "left", "middle" или "right"
    eventObj.mousePosition() // вернет объект {x: число, y: число}
    eventObj.mousePosition().x // координата курсора по оси OX
    eventObj.mousePosition().y // координата курсора по оси OY
    eventObj.target() // текущий элемент, при всплывании события
    this // ссылка на <div> c идентификатором "container"
})
События клавиатуры
$(document).bind('keydown', function() {
    $.event(arguments[0]).key() // код нажатой клавиши
 })
Стандартное действие браузера и всплывание событий
$(document.forms[0]).bind('submit', function() {
    var eventObj = $.event(arguments[0])
    eventObj.preventDefault() // предотвращает стандартное действие
    eventObj.stopPropagation() // останавливает "всплывание" события
    eventObj.stop() // выполняет 2 предыдущих метода
})

Для управления предотвращением стандартного действия браузера (preventDefualt/returnValue), методы bind(…) и unbind(…) могут принимать, в качестве 3-го параметра, значения true или false, а так же предусмотрен специальный метод useDefault(…):

// выполнять автоматически preventDefault
$(document.forms[0]).bind('submit', func, false)

// отменить автоматическое срабатывание preventDefault
$(document.forms[0]).useDefault('submit', true)

Работа со списками элементов

Еще одна функция-конструктор $.list(…) создает обертку для списка DOM-элементов (узлов с nodeType == 1) и предоставляет набор методов:

var list = $.list(document.getElementsByTagName('div'))

// или
var list = new $.list(document.getElementsByTagName('div'))

Если отправить в функцию набор, содержащий не только элементы, но и текстовые узлы, то она автоматически оставит в списке только элементы:

var list = $.list(document.body.childNodes)

Так же, в качестве второго аргумента, можно указать значение false или функцию-фильтр. Если указано значение false, то автоматическая фильтрация узлов по значению свойства nodeType не производится, это может быть использовано для увеличения производительности, если вы уверены, что передаваемая вами коллекция элементов не содержит текстовых узлов. Функция-фильтр вызывается в контексте каждого элемента списка с nodeType == 1, для того чтобы включать элемент в список, функция должна вернуть значение true.

var list = $.list(document.getElementsByTagName('*'), false)

Рассмотрим работу варианта с функцией-фильтром на конкретном примере, допустим есть следующий XHTML-код:

<ul id="list-items">
    <li>1st list item</li>
    <li>2nd list item</li>
    <li>3rd list item</li>
    <li>4th list item</li>
    <li>5th list item</li>
</ul>

Добавим CSS-класс highlight всем четным элементам <li> в списке <ul> c идентификатором list-items:

$.list($('list-items').node.childNodes, function(i) {
    return i % 2 == 0;
}).each(function() {
    $(this).addClass('highlight');
})

Существуют способы сделать это короче:

$.list($('list-items').node.childNodes}).each(function(i) {
    if(i % 2 == 0) $(this).addClass('highlight')
});

// или
$.list($('list-items').node.childNodes, function(i) {
    return i % 2 == 0;
}).each('addClass', 'highlight')

// или
$('list-items').child().filter(function(i) {
    return i % 2 == 0;
}).each('addClass', 'highlight')

// или
$('list-items').child().each(function(i) {
    if(i % 2 == 0) $(this).addClass('highlight')
})

Как видим, некоторые методы (child, filter и др.) возвращают экземпляр объекта $.list.

Сам список можно получить следующим образом:

var items = $.list(document.body.childNodes).items

Остальные методы работы со списками смотрите в таблице ниже.

Методы js-core

Разобьем методы на группы по объектам, к которым они относятся.

Методы доступные через прототип функции core(…) или $(…)

$(document.body).append('h1').text('Пример');
Метод Варианты вызова Возвращаемое значение Действие
DOM
parent .parent() {node:HTMLElement} Получить родительский узел
append .append(‘tagName’) {node:HTMLElement} Добавить новый узел в конец списка дочерних элементов текущего узла
.append(HTMLElement) Переместить существующий узел в конец списка дочерних элементов текущего узла
prepend .prepend(‘tagName’) {node:HTMLElement} Добавить новый узел в начало списка дочерних элементов текущего узла
.prepend(HTMLElement) Переместить существующий узел в начало списка дочерних элементов текущего узла
after .after(‘tagName’) {node:HTMLElement} Добавить новый узел после текущего элемента
.after(HTMLElement) Поместить существующий узел после текущего элемента
before .before(‘tagName’) {node:HTMLElement} Добавить новый узел перед текущим элементом
.before(HTMLElement) Поместить существующий узел перед текущим элементом
appendTo appendTo(‘id’) {node:HTMLElement} Добавить текущий узел в конец списка дочерних элементов узла с указанным идентификатором
appendTo(HTMLElement) Добавить текущий узел в конец списка дочерних элементов указанным узла
prependTo prependTo(‘id’) {node:HTMLElement} Добавить текущий узел в начало списка дочерних элементов узла с указанным идентификатором
prependTo(HTMLElement) Добавить текущий узел в начало списка дочерних элементов указанным узла
insertAfter insertAfter(‘id’) {node:HTMLElement} Поместить текущий узел после элемета с указанным идентификатором
insertAfter(HTMLElement) Поместить текущий узел после указанного элемента
insertBefore insertBefore(‘id’) {node:HTMLElement} Поместить текущий узел перед элеметом с указанным идентификатором
insertBefore(HTMLElement) Поместить текущий узел перед указанным элементом
next .next() {node:HTMLElement} Получить следующий элемент
.next(‘tagName’) Получить следующий элемент с указанным именем тега
prev .prev() {node:HTMLElement} Получить предыдущий элемент
.prev(‘tagName’) Получить предыдущий элемент с указанным именем тега
clone .clone() {node:HTMLElement} Получить копию текущего узла вместе с дочерними элементами
.clone(false) Получить копию текущего узла без дочерних элементов
replace .replace(‘tagName’) {node:HTMLElement} Заменить текущий узел новым элементом
.replace(HTMLElement) Заменить текущий узел существующим элементом
wrap .wrap(‘tagName’) {node:HTMLElement} Обернуть текущий узел новым элементом
.wrap(‘tagName’, ‘outside’)
.wrap(‘tagName’, ‘inside’) Обернуть все дочерние узлы текущего элемента новым узлом
.wrap(HTMLElement) Обернуть текущий узел существующим элементом
.wrap(HTMLElement, ‘outside’)
.wrap(HTMLElement, ‘inside’) Обернуть все дочерние узлы текущего элемента существующим узлом
empty .empty() {node:HTMLElement} Удалить все дочерние узлы текущего элемента
remove .remove() null Удалить текущий элемент вместе с дочерними узлами
text .text() string Получить свойство innerText текущего элемента
.text(‘string’) {node:HTMLElement} Удалить все дочерние узлы текущего элемента и поместить в него новый текстовый узел
html .html() string Получить свойство innerHTML текущего элемента
.html(‘string’) {node:HTMLElement} Изменить свойство innerText текущего элемента
exist .exist() true|false Проверить существование узла
.exist(func) {node:HTMLElement} Запустить функцию func, если узел существует
.exist(func1, func2) Запустить функцию func1, если узел существует, иначе — запустить func2
.exist(null, func) Запустить функцию func, если узел отсутствует
el .el() HTMLElement Получить прямую ссылку на текущий элемент
.el(‘id’) {node:HTMLElement} Заменить текущий элемент узлом с указанным идентификатором
.el(HTMLElement) Заменить текущий элемент существующим узлом
id .id() string Получить идентификатор текущего узла
.id(‘string’) {node:HTMLElement} Изменить идентификатор текущего узла
is .is() true|false Проверить существование узла
.is({attr: ‘value’}) Если хотя бы одно из значений указанных атрибутов не совпадает со значениями соответствующих атрибутов текущего узла, вернуть false, иначе — true
.is({attr1: ‘value1′, attr2: ‘value2′, …})
.is(‘tagName’)
.is({attr: ‘value’}, ‘tagName’)
.is({attr1: ‘value1′, attr2: ‘value2′, …}, ‘tagName’)
val .val() string Получить свойство value текущего элемента ввода
.val(‘string’) {node:HTMLElement} Изменить свойство value текущего элемента ввода
enabled .enabled() true|false Проверить активность текущего элемента ввода
.enabled(true) {node:HTMLElement} Включить текущий элемент ввода
.enabled(false) Выключить текущий элемент ввода
attr .attr(‘attr’) * Получить значение указанного атрибута текущего узла
.attr(['attr'])
.attr(‘attr1 attr2 …’) array Получить массив значений указанных атрибутов текущего узла
.attr(['attr1', 'attr2', …])
.attr({attr: ‘value’}) {node:HTMLElement} Изменить значения указанных атрибутов текущего узла
.attr({attr1: ‘value1′, attr2: ‘value2′, …})
removeAttr .removeAttr(‘attr’) {node:HTMLElement} Удалить значения указанных атрибутов текущего узла
.removeAttr(['attr'])
.removeAttr(‘attr1 attr2 …’)
.removeAttr(['attr1', 'attr2', …])
child .child() {items:ElementsList} Получить все дочерние элементы текущего узла
.child(‘tagName’) Получить все дочерние элементы текущего узла с указанными именами тегов
.child(‘tagName1 tagName2 …’)
.child(['tagName'])
.child(['tagName1', 'tagName2', …])
.child(true) Получить все дочерние элементы текущего узла на всех уровнях вложенности
.child(‘tagName’, true) Получить все дочерние элементы текущего узла на всех уровнях вложенности с указанными именами тегов
.child(‘tagName1 tagName2 …’, true)
.child(['tagName'], true)
.child(['tagName1', 'tagName2', …], true)
find .find(‘attr’) {items:ElementsList} Получить все дочерние элементы текущего узла, у которых совпадают все указанные атрибуты; поиск элементов ведется на всех уровнях вложенности
.find(['attr'])
.find(‘attr1 attr2 …’)
.find(['attr1', 'attr2'])
.find({attr: ‘value’})
.find({attr1: ‘value1′, attr2: ‘value2′, …})
.find(‘attr’, ‘tagName’)
.find(['attr'], ‘tagName’)
.find(‘attr1 attr2 …’, ‘tagName’)
.find(['attr1', 'attr2', …], ‘tagName’)
.find({attr: ‘value’}, ‘tagName’)
.find({attr1: ‘value1′, attr2: ‘value2′, …}, ‘tagName’)
findAttr .findAttr(‘attr’, ‘value’) {items:ElementsList} Получить все дочерние элементы текущего узла, в значении указанного атрибута которых встречается хотя бы одно из указанных значений; поиск значений ведется по границе слов (/\bValue\b/); поиск элементов ведется на всех уровнях вложенности
.findAttr(‘attr’, ['value'])
.findAttr(‘attr’, ‘value1 value2 …’)
.findAttr(‘attr’, ['value1', 'value2', …])
.findAttr(‘attr’, ‘value’, ‘tagName’)
.findAttr(‘attr’, ['value'], ‘tagName’)
.findAttr(‘attr’, ‘value1 value2 …’, ‘tagName’)
.findAttr(‘attr’, ['value1', 'value2', …], ‘tagName’)
findClass .findClass(‘class’) {items:ElementsList} Получить все дочерние элементы текущего узла, в атрибуте className которых встречается хотя бы один из указанных CSS-классов; поиск элементов ведется на всех уровнях вложенности
.findClass(['class'])
.findClass(‘class1 class2 …’)
.findClass(['class1', 'class2', …])
.findClass(‘class’, ‘tagName’)
.findClass(['class'], ‘tagName’)
.findClass(‘class1 class2 …’, ‘tagName’)
.findClass(['class1', 'class2', …], ‘tagName’)
serialize .serialize() string Получить HTML-код текущего элемента вместе с кодом самого элемента; идентично свойству outerHTML в IE
CSS
css .css(‘property’) string Получить значение указанного CSS-свойства текущего элемента
.css(['property'])
.css(‘property1 property2 …’) array Получить массив значений указанных CSS-свойств текущего элемента
.css(['property1', 'property2', …])
.css({property: ‘value’}) {node:HTMLElement} Изменить указанные CSS-свойства текущего элемента
.css({property1: ‘value1′, property2: ‘value2′, …})
hide .hide() {node:HTMLElement} Скрыть текущий элемент
show .show() {node:HTMLElement} Сделать текущий элемент видимым
.show(‘displayType’) Сделать текущий элемент видимым и присвоить CSS-свойству display указанное значение (может понадобится для отображения списков, строчных элементов и др.)
toggle .toggle() {node:HTMLElement} Скрыть текущий элемент, если он отображается, иначе — сделать его видимым
.toggle(‘displayType’)
visible .visible() true|false Проверить отображается ли текущий элемент
opacity .opacity() number Получить уровень непрозрачности текущего элемента
.opacity(0.0—1.0) {node:HTMLElement} Изменить уровень непрозрачности текущего элемента
hasClass .hasClass() true|false Проверить наличие CSS-классов текущего элемента
.hasClass(‘className’)
.hasClass(['className'])
.hasClass(‘className1 className2 …’)
.hasClass(['className1', 'className2', …])
addClass .addClass(‘className’) {node:HTMLElement} Добавить CSS-классы текущему элементу
.addClass(['className'])
.addClass(‘className1 className2 …’)
.addClass(['className1', 'className2', …])
removeClass .removeClass(‘className’) {node:HTMLElement} Удалить CSS-классы текущему элементу
.removeClass(‘className’)
.removeClass(['className'])
.removeClass(‘className1 className2 …’)
.removeClass(['className1', 'className2', …])
toggleClass .toggleClass(‘className’) {node:HTMLElement} Удалить имеющиеся CSS-классы и добавить недостающие
.toggleClass(['className'])
.toggleClass(‘className1 className2 …’)
.toggleClass(['className1', 'className2', …])
.toggleClass(‘className1′, ‘className2′) Заменить CSS-класс с именем className1 на className2
.toggleClass(['className1'], ['className2'])
.toggleClass(‘className1 className2 …’, ‘className3 className4 …’) Последовательно заменить className1 на className3, className2 на className4
.toggleClass(['className1', 'className2', …], ['className3', 'className4', …])
Events (события)
useDefault .useDefault(‘eventType’, false) {node:HTMLElement} Добавить в обработчик указанного события для текущего элемента функцию, предотвращающую стандартное действие браузера
.useDefault(‘eventType’, true) Удалить из обработчика указанного события для текущего элемента функцию, предотвращающую стандартное действие браузера
bind .bind(‘eventType’, function) {node:HTMLElement} Добавить в обработчик указанного события для текущего элемента функцию
.bind(‘eventType’, function, false) Добавить в обработчик указанного события для текущего элемента функцию и автоматически выполнить .useDefault(‘eventType’, false)
.bind(‘eventType’, function, true) Добавить в обработчик указанного события для текущего элемента функцию и автоматически выполнить .useDefault(‘eventType’, true)
unbind .unbind(‘eventType’, function) {node:HTMLElement} Удалить из обработчика указанного события для текущего элемента функцию
.unbind(‘eventType’, function, false) Удалить из обработчика указанного события для текущего элемента функцию и автоматически выполнить .useDefault(‘eventType’, false)
.unbind(‘eventType’, function, true) Удалить из обработчика указанного события для текущего элемента функцию и автоматически выполнить .useDefault(‘eventType’, true)
AJAX (Необходимо подключить AJAX-модуль)
load Смотрите в соответствующем разделе {node:HTMLElement} Заменить содержимое текущего узла на данные, полученные с помощью AJAX-запроса

Методы и атрибуты объекта core или $

Как бы странно это не звучало, но в JavaScript такое возможно, любая функция одновременно является объектом и может изменть свои атрибуты и методы. Использовать их можно следующим образом:

$.ready(func) // выполнить функцию по событию "DOMContentLoaded"
$.t('h1 h2 h3 h4 h5 h6') // получить все заголовки в документе
$.c('selected') // получить все элементы с классом "selected"

Подробнее обо всех методах объекта core или $ далее в таблице.

Метод Варианты вызова Возвращаемое значение Действие
Основные
ready .ready(func) undefined Выполнить функцию func по событию DOMContentLoaded
context .context(func, obj) function Добавить специальную обертку для функции func, чтобы она всегда выполнялась в контексте объекта obj
n .n(‘tagName’) {node:HTMLElement} Создать новый элемент
t .t() {items:ElementsList} Получить список всех тегов
.t(‘tagName’) Получить список указанных тегов
.t(['tagName'])
.t(‘tagName1 tagName2 …’)
.t(['tagName1', 'tagName2', …])
c .c(‘class’) {items:ElementsList} Получить все элементы, в атрибуте className которых встречается хотя бы один из указанных CSS-классов; поиск элементов ведется во всем документе
.c(['class'])
.c(‘class1 class2 …’)
.c(['class1', 'class2', …])
.c(‘class’, ‘tagName’)
.c(['class'], ‘tagName’)
.c(‘class1 class2 …’, ‘tagName’)
.c(['class1', 'class2', …], ‘tagName’)
a .a(‘attr’) {items:ElementsList} Получить все элементы, у которых совпадают все указанные атрибуты; поиск элементов ведется во всем документе
.a(['attr'])
.a(‘attr1 attr2 …’)
.a(['attr1', 'attr2'])
.a({attr: ‘value’})
.a({attr1: ‘value1′, attr2: ‘value2′, …})
.a(‘attr’, ‘tagName’)
.a(['attr'], ‘tagName’)
.a(‘attr1 attr2 …’, ‘tagName’)
.a(['attr1', 'attr2', …], ‘tagName’)
.a({attr: ‘value’}, ‘tagName’)
.a({attr1: ‘value1′, attr2: ‘value2′, …}, ‘tagName’)
f .f(‘attr’, ‘value’) {items:ElementsList} Получить все элементы, в значении указанного атрибута которых встречается хотя бы одно из указанных значений; поиск значений ведется по границе слов (/\bValue\b/); поиск элементов ведется во всем документе
.f(‘attr’, ['value'])
.f(‘attr’, ‘value1 value2 …’)
.f(‘attr’, ['value1', 'value2', …])
.f(‘attr’, ‘value’, ‘tagName’)
.f(‘attr’, ['value'], ‘tagName’)
.f(‘attr’, ‘value1 value2 …’, ‘tagName’)
.f(‘attr’, ['value1', 'value2', …], ‘tagName’)
makeArray .makeArray(list) array Преобразовать список в массив
forEach .forEach(array, function(element, index, array) {…}) array Последовательно выполнить функцию для каждого элемента массива или объекта; чтобы прервать цикл, функция должна вернуть false
.forEach(array, function(element, index, array) {…}, context)
.forEach(object, function(element, index, array) {…}) object
.forEach(object, function(key, value, object) {…}, context)
extend .extend(object, hash) object Расширить объект object методами и атрибутами объекта hash; имеющиеся атрибуты и методы перезаписываются
trim .trim(‘string’) string Удалить все пробельные символы в начале и конце строки
.trim.both(‘string’)
.trim.left(‘string’) Удалить все пробельные символы в начале строки
.trim.right(‘string’) Удалить все пробельные символы в конце строки
.trim.spaces(‘string’) Удалить все повторяющиеся пробельные символы
.trim.all(‘string’) Выполнить все виды преобразований
list .list(NodeList) {items:ElementsList} Получить список элементов с nodeType==1
new $.list(NodeList)
.list(NodeList, false) Получить список элементов; используйте этот вариант для увеличения производительности в случае, если уверены, что в коллекции нет текстовых и других узлов, кроме элементов
new $.list(NodeList, false)
.list(NodeList, function(index){…}) Получить список элементов используя функцию-фильтр; если функция возвращает true, элемент включается в коллекцию
new $.list(NodeList, function(index){…})
timer .timer(timeout, func) object Получить объект «timer»; методы этого объекта приведены в отдельной таблице
new $.timer(timeout, func)
.timer(timeout, func, [arguments])
new $.timer(timeout, func, [arguments])
event .event(eventObject) {object:eventObject} Получить объект-событие; методы этого объекта приведены в отдельной таблице
new $.event(eventObject)
ajax .ajax() {xhr:XMLHttpRequest} Получить объект для работы с AJAX; методы этого объекта приведены в отдельной таблице;
new $.ajax()
Вспомогательные
ie .ie number|undefined Номер версии Internet Explorer
cache .cache object Кэш элементов по идентификаторам
clear .clear(HTMLElement) HTMLElement Очищает кэш
id .id(‘string’) HTMLElement Получить элемент по идентификатору используя кэш
.id(HTMLElement)
tag .tag({}) DOMNodeList Получить коллекцию всех элементов
.tag({tag: ‘tagName’}) Получить коллекцию всех элементов с указанным именем тега
.tag({node: HTMLElement}) Получить коллекцию дочерних элементов указанного узла
.tag({tag: ‘tagName’, node: HTMLElement}) Получить коллекцию дочерних элементов с указанным именем тега
tags .tags({}) array Получить список элементов; поиск ведется во всем документе
.tags({tag: ‘tagName’})
.tags({tag: ['tagName']})
.tags({tag: ‘tagName1 tagName2 …’})
.tags({tag: ['tagName1', 'tagName2', …])
.tags({node: HTMLElement}) Получить список дочерних элементов указанного узла; поиск ведется на всех уровнях вложенности
.tags({node: HTMLElement, tag: ‘tagName’})
.tags({node: HTMLElement, tag: ['tagName']})
.tags({node: HTMLElement, tag: ‘tagName1 tagName2 …’})
.tags({node: HTMLElement, tag: ['tagName1', 'tagName2', …])
child .child() array Получить все дочерние узлы
.child(HTMLElement, ‘tagName’) Получить все дочерние узлы с указанными именами тегов
.child(HTMLElement, ['tagName'])
.child(HTMLElement, ‘tagName1 tagName2 …’)
.child(HTMLElement, ['tagName', 'tagName2', …])
create .create(‘tagName’) HTMLElement Создать новый элемент
.create(HTMLElement)
insert .insert(parentNode, thisNode, beforeNode) thisNode (HTMLElement) Вставить элемент thisNode в список дочерних элементов узла parentNode перед элементом beforeNode
.insert(parentNode, ‘tagName’, beforeNode) Вставить новый узел в список дочерних элементов узла parentNode перед элементом beforeNode
sibling .sibling(HTMLElement, ‘nextSibling’) HTMLElement Найти соседний элемент
.sibling(HTMLElement, ‘previousSibling’)
.sibling(HTMLElement, ‘nextSibling’, ‘tagName’) Найти соседний элемент c указанным именем тега
.sibling(HTMLElement, ‘previousSibling’, ‘tagName’)
bind .bind(HTMLElement, ‘eventType’, func) undefined Добавить обработчик события
unbind .unbind(HTMLElement, ‘eventType’, func) undefined Удалить обработчик события
css .css(HTMLElement, ‘CSS-property’) string Получить значение CSS-свойства
inStr .inStr(‘string’, ‘substring’) number Найти строку substring в строке string по шаблону /\bsubstring\b/
toArray .toArray(‘string’) array Разбить строку на элементы по шаблону /\s+/
.toArray(array)
attr .attr({attr: ['attr']}) array Получить список элементов с указанными атрибутами; поиск ведется на всех уровнях вложенности
.attr({attr: ['attr1', 'attr2', …]})
.attr({tag: ‘tagName’, attr: ['attr']})
.attr({tag: ‘tagName’, attr: ['attr1', 'attr2', …]})
.attr({node: HTMLElement, attr: ['attr']}) Получить список дочерних элементов с указанными атрибутами; поиск ведется на всех уровнях вложенности
.attr({node: HTMLElement, attr: ['attr1', 'attr2', …]})
.attr({node: HTMLElement, tag: ‘tagName’, attr: ['attr']})
.attr({node: HTMLElement, tag: ‘tagName’, attr: ['attr1', 'attr2', …]})
.attr({node: HTMLElement, attr: {attr: ‘value’}}) undefined Изменить значения атрибутов указанного узла
.attr({node: HTMLElement, attr: {attr1: ‘value1′, ‘attr2′: ‘value2′, …}})
value .value({attr: {attr: ‘value’}}) array Получить элементы, у которых совпадают все указанные атрибуты; поиск ведется по всему документу
.value({attr: {attr1: ‘value1′, ‘attr2′: ‘value2′, …}})
.value({tag: ‘tagName’, attr: {attr1: ‘value1′, ‘attr2′: ‘value2′, …}})
.value({node: HTMLElement, attr: {attr1: ‘value1′, ‘attr2′: ‘value2′, …}}) Получить все дочерние элементы, у которых совпадают все указанные атрибуты; поиск ведется на всех уровнях вложенности
.value({node: HTMLElement, tag: ‘tagName’, attr: {attr1: ‘value1′, ‘attr2′: ‘value2′, …}})
values .values({attr: ['attr'], value: ‘string’, attr: ‘string’}) array Получить все элементы, в значении указанного атрибута которых встречается хотя бы одно из указанных значений; поиск значений ведется по границе слов (/\bValue\b/); поиск элементов ведется на всех уровнях вложенности
.values({attr: ['attr1', 'attr2', …], value: ‘string’, attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr'], value: ‘string’, attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ‘string’, attr: ‘string’})
.values({node: HTMLElement, attr: ['attr'], value: ‘string’, attr: ‘string’})
.values({node: HTMLElement, attr: ['attr1', 'attr2', …], value: ‘string’, attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr'], value: ‘string’, attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ‘string’, attr: ‘string’})
.values({attr: ['attr'], value: ['string'], attr: ‘string’})
.values({attr: ['attr1', 'attr2', …], value: ['string'], attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr'], value: ['string'], attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ['string'], attr: ‘string’})
.values({node: HTMLElement, attr: ['attr'], attr: ‘string’})
.values({node: HTMLElement, attr: ['attr1', 'attr2', …], value: ['string'], attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr'], value: ['string'], attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ['string'], attr: ‘string’})
.values({attr: ['attr'], value: ‘value1 value2 …’, attr: ‘string’})
.values({attr: ['attr1', 'attr2', …], value: ‘value1 value2 …’, attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr'], value: ‘value1 value2 …’, attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ‘value1 value2 …’, attr: ‘string’})
.values({node: HTMLElement, attr: ['attr'], value: ‘value1 value2 …’, attr: ‘string’})
.values({node: HTMLElement, attr: ['attr1', 'attr2', …], value: ‘value1 value2 …’, attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr'], value: ‘value1 value2 …’, attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ‘value1 value2 …’, attr: ‘string’})
.values({attr: ['attr'], value: ['value1', 'value2', …], attr: ‘string’})
.values({attr: ['attr1', 'attr2', …], value: ['value1', 'value2', …], attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr'], value: ['value1', 'value2', …], attr: ‘string’})
.values({tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ['value1', 'value2', …], attr: ‘string’})
.values({node: HTMLElement, attr: ['attr'], value: ['value1', 'value2', …], attr: ‘string’})
.values({node: HTMLElement, attr: ['attr1', 'attr2', …], value: ['value1', 'value2', …], attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr'], value: ['value1', 'value2', …], attr: ‘string’})
.values({node: HTMLElement, tag: ‘tagName’, attr: ['attr1', 'attr2', …], value: ['value1', 'value2', …], attr: ‘string’})

Методы работы с таймером

В js-core вводит специальный объект для более удобного использования встроенных методов setTimeout и setInterval. Получить этот объект можно при помощи функции конструктора $.timer(…) или core.timer(…):

// повторить выполнение функции 5 раз с задержкой 100 мс
$.timer(100, function() {…}).repeat(5)

// выполнять функцию с задержкой 50 мс
core.timer(50, function() {…}).start()

Подробнее, об остальных методах, в таблице ниже:

Метод Варианты вызова Возвращаемое значение Действие
start .start() object Запустить таймер
stop .stop() object Остановить таймер
repeat .repeat(amount) object Запустить таймер и выполнить указанное количество раз
.repeat(amount, func) Запустить таймер и выполнить указанное количество раз; по окончании запустить callback-функцию func
.repeat(amount, func, [arguments])

Методы работы со списками узлов

Все методы фреймворка для работы со списками узлов доступны через прототип функции $.list(…), которая может быть использована в качестве конструктора любым из представленных ниже способов:

var list = $.list(document.getElementsByTagName('div'))

// или
var list = new $.list(document.getElementsByTagName('div'))

// или
var list = core.list(document.getElementsByTagName('div'))

// или
var list = new core.list(document.getElementsByTagName('div'))

Некоторые функции фреймворка автоматически создают подобные списки, например:

var list = $.t('div');

В результате в переменной list будет ссылка на объект, содержащий список узлов, над которым можно произвонить действия, например, добавим всем найденным элементам CSS-класс highlight:

list.each('addClass', 'highlight');

Подробнее обо всех методах функции-конструктора $.list(…) далее в таблице:

Метод Варианты вызова Возвращаемое значение Действие
items .items ElementsList Получить прямую ссылку на список или массив узлов
item .item(number) {node:HTMLElement} Получить элемент списка с указанным номером
last .last() {node:HTMLElement} Получить последний элемент списка
size .size() number Получить количество элементов в списке
each .each(function(HTMLElement, index, ElementsList){…}) {items:ElementsList} Последовательно выполнить функцию для каждого элемента списка; чтобы прервать цикл, функция должна вернуть false
.each(‘method’, arguments) Последовательно выполнить указанный метод для каждого элемента списка
filter .filter(‘method’, arguments) {items:ElementsList} Получить новый список элементов из текущего используя метод-фильтр; если метод возвращает true, элемент включается в новую коллекцию
.filter(NodeList, function(index){…}) Получить новый список элементов из текущего используя функцию-фильтр; если функция возвращает true, элемент включается в новую коллекцию

Методы работы с объектом-событие

Обработка событий, как говорилось ранее, один из самых трудных моментов, но используя js-core, вы избавить себя от ряда проблем.

function(e) {
    $.event(e).preventDefault();
}

Подробнее, об остальных методах, в таблице ниже:

Метод Варианты вызова Возвращаемое значение Действие
preventDefault .preventDefault() {object:eventObject} Предотвратить стандартное действие браузера
stopPropagation .stopPropagation() {object:eventObject} Остановить всплывание события
stop .stop() {object:eventObject} Выполнить два предыдущих метода
target .target() HTMLElement Получить текущий элемент, на котором сработало событие
mouseButton .mouseButton() left|middle|right Узнать, какая кнопка мыши была нажата
mousePosition .mousePosition() {x:number,y:number} Получить координаты курсоры мыши
key .key() number Получить код нажатой клавиши

Методы работы с AJAX

Для того чтобы получить доступ к методам для работы с AJAX в js-core, вам нужно подключить соответствующий модуль, который находится в отдельном файле. Такое разделение было сделано по причине того, что в дальнейшем планируется значительно увеличить функционал этого модуля, что неминуемо приведет к увеличению его размеров, но не каждое JavaScript-приложение использует AJAX для передачи данных.

На данный момент (версия модуля 0.2.5) доступно 4 метода, которые могут принимать следующие аргументы:

// объект с параметрами
var parametrs = {
    method: 'GET'|'POST',      // по умолчанию GET
    url: 'url-encoded-string', // по умолчанию location.href
    async: true|false,         // по умолчанию true
    user: 'string',            // по умолчанию null
    password: 'string',        // по умолчанию null
    params: {param: 'value'},  // по умолчанию null
    processData: true|false,   // по умолчанию false
    timeout: number,           // по умолчанию 0
    contentType: 'string',// по умолчанию application/x-www-form-urlencoded
    dataType: 'string',        // по умолчанию */*
    requestHeaders: {'name': 'content'}, // по умолчанию null
    protocol: 'string'         // по умолчанию http:
}
// callback-функции
function success(responseText [, xhr]) {...}
function error(responseText [, xhr]) {...}

Ни один из аргументов объекта parametrs не обязателен, как и callback-функции. Метод $(…).load(…) выполняет callback-функции в контексте текущего элемента, остальные — AJAX-объекта.

$('container').text('loading…').load(parametrs, success, error)

Не забывайте, что в JavaScript действует «правило одного источника», поэтому передачу данных можно производить только в переделах одного домена.

Метод Варианты вызова Возвращаемое значение Действие
load $(…).load(parametrs) {node:HTMLElement} Заменить содержимое текущего узла на данные, полученные с помощью AJAX-запроса
$(…).load(parametrs, success)
$(…).load(parametrs, success, error)
$(…).load(parametrs, null, error)
$.get $.get(parametrs) object Выполнить GET-запрос средствами AJAX
$.get(parametrs, success)
$.get(parametrs, success, error)
$.get(parametrs, null, error)
$.post $.post(parametrs) object Выполнить POST-запрос средствами AJAX
$.post(parametrs, success)
$.post(parametrs, success, error)
$.post(parametrs, null, error)
$.getJSON $.getJSON(parametrs) object Выполнить запрос средствами AJAX и автоматически преобразовать пришедшие от сервера данные в JavaScript-объект
$.getJSON(parametrs, success)
$.getJSON(parametrs, success, error)
$.getJSON(parametrs, null, error)

Создание расширений для js-core

Фреймворк имеет удобный и простой механизм расширения стандартного функционала пользовательскими методами:

core.prototype.newMethod = function() {
    // что-то делаем с this.node
    return this; // для обарзования цепочек
}

Добавим метод defaultValue(…), который служит, чтобы установить значение по умолчанию для элемента ввода:

core.prototype.defaultValue = function(str) {
    if(!this.node.value) this.node.value = str;
    return this.bind('focus', function() {
        if(this.value == str) this.value = '';
    }).bind('blur', function() {
        if(!core.trim(this.value)) this.value = str;
    });
};

// используем
$(HTMLInputElement).defaultValue('Найти');

Как видим, механизм расширения предельно прост, достаточно добавить свой метод в прототип объекта core, а для того, чтобы организовать возможность построения цепочек вызовов, можно вернуть в своем методе контекст вызова this.

Что дальше?

Я планирую поддерживать и развивать проект. За дальнейшими обновлениями следите на сайте www.js-core.ru. В скором времени там начнет появляться документация с примерами для каждого метода.

Дальнейшие планы по наращиванию функционала:

  • Анимация (fadeIn, fadeOut, slideToggle), которую вы можете реализовать и сейчас, для этого есть набор необходимых методов (opacity, timer, hide, show и др.);
  • Обработка форм, маскированный ввод;
  • Расширение функциональности AJAX-модуля, внедрение глобальных AJAX-событий и очередей перезапускающихся запросов;
  • Создание набора готовых элементов интерфейса;
  • Подавление других фреймворков

В каком порядке будут появляться дополнения, не знаю, могу только сказать, что уже начал работать над анимацией.

На этом закончим статью, надеюсь, вам пришлись по вкусу способы, предлагаемые фреймворком js-core, решения задач, и на его основе вы будете создавать современные и динамичные сайты и веб-приложения.

Скачать

Скачать можно на странице проекта в сервисе Google Code или с сайта www.js-core.ru.

Подписаться на обновления блога

Вам понравился наш блог, хотите следить за обновлениями? Подпишитесь на RSS рассылку или рассылку по электронной почте. Так же вы можете следить за нами в Twitter.

Категории: JavaScript, js-core | Комментировать

Комментарии (11)

  1. Артём Курапов / 08.01.2009 в 12:43

    Может я глупость скажу, но разве вы не знакомы с jquery или prototype? Потому что судя по описанию эта $ функция прям аналог той что в prototype, и я бы не сказал что самая удачная.

  2. Sam / 08.01.2009 в 14:59

    Догоняем монстров потихоньку…

    // ‘conteiner’ очень глаз режет. Может ‘container’?

  3. Octane / 08.01.2009 в 16:11

    Артём Курапов, нет функция «$(…)» не аналогична одноименным функциям в jQuery и Prototype.

    В jQuery эта функция может принимать CSS-селекторы вместе с контекстом поиска, прямые ссылки на элементы, функции, запускаемые по событию DOMContentLoaded, может и еще что-то упустил… в общем это сложная и универсальная функция.

    В Prototype функция «$(…)» ищет элементы по идентификатору и возвращает прямые ссылки на DOM-узлы, которые проходят обработку Element.extend(element).

    В js-core функция «$(…)» служит для поиска элемента по идентификатору и возвращает объект вида {node: HTMLElement}, а через прототип его функции-конструктора, становится доступен набор методов для работы с DOM, CSS, AJAX и событиями.

    В чем вы считаете не удачность ее реализации?

    Sam, спасибо, поправлю :) а до монстров постараюсь не доводить, все таки хочется сохранить легкость и быстродействие, иначе зачем еще один «монстрофреймворк»

  4. RSmichyk / 09.01.2009 в 17:57

    Класна стаття

  5. seoengineer / 25.01.2009 в 01:19

    отличная работа

  6. Denis Usenko / 01.02.2009 в 02:25

    Багрепорт маленький.
    Сначала отсылка к w3c:
    4. Синтаксис CSS2 и базовые типы данных.
    4.1.3 Символы и регистр
    http://www.w3.org/TR/1998/REC-CSS2-19980512/syndata.html#q4
    http://www.umade.ru/resources/specifications/CSS2/syndata.html#q4
    Цитата:
    In CSS2, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [A-Za-z0-9] and ISO 10646 characters 161 and higher, plus the hyphen (-); they cannot start with a hyphen or a digit.

    Отсюда — нельзя искать класс таким регэкспом: /\bSomeString\b/ (это в функе inStr)
    Например на странице есть код:

    id ="d1" class="some-class"

    теперь спросим:

    $('d1').hasClass('some')

    ответит true
    Здесь вообще не нужны регулярки:

    (' ' + element.className + ' ').indexOf(' ' + someClass + ' ') >= 0

    В целом либа понравилась, меня убивает, например, что джиквери обильно обвешивает HTMLElement’ы на ходу (и без оптимизации для нормальных браузеров с HTMLElement, как это сделано в последних прототайпах). Здесь же это аккуратнее, покольку элемент лежит в свойстве node. Здорово так же, что почти ничего лишнего нет, так и держитесь этого подхода.

    Я не совсем уверен, может это противоречит идее либы, но. Почему forEach для всех рукотворный? Может восполнить его в Array.prototype для мсие (а также map, filter, indexOf, lastIndexOf, every, some. Во всех остальных все это уже есть) и использовать уже готовый в core.forEach?

  7. Octane / 01.02.2009 в 16:38

    Спасибо большое за отзыв и багрепорт :)

    Поиск по границе слов уже исправлен в версии 2.7.3

    В старых версиях использовался, где это было возможно, нативный forEach, но в процессе оптимизации от него пришлось отказаться, т.к. он не позволяет сделать break. Кстати если почитать описание forEach в MDC, там в комментариях есть предложения добавить эту возможность, но видимо уже поздно что-то менять. Хотя в последних версиях я все больше отказываюсь от дополнительных анонимных функций, возникающих при использовании подобных методов в пользу обычного while, из-за скорости работы в IE.

    Скорее всего нативный forEach и его реализация для старых браузеров появится в составе расширения js-core для работы с массивами, а так же всякие indexOf, some, map, unique и др. для Array.

    Более свежая версия документации доступна на сайте js-core.ru и в архиве на странице проекта в сервисе Google Code.

  8. Octane / 01.02.2009 в 21:29

    Блин про removeClass и toggleClass совсем забыл, в следующей версии 2.7.4 и там исправлю поиск с использованием \b.

  9. Denis Usenko / 12.02.2009 в 05:12

    Продложаю потихоньку просматривать код, возник вопрос. Проверка «this.core» в конструкторе core:
    if(this.core) return new core(arg);
    это «если в контексте window то вернуть новый экземпляр core» ? Если так, то что будет если долларом воспользоваться в конструкторе какого либо объекта?

  10. Octane / 12.02.2009 в 14:20

    Контекст выполнения и область видимости разные вещи. Глобальные функции и методы других объектов не меняют свой контекст выполнения при явном вызове. Это легко проверить, создадим объект:

    var obj = {
        name: 'obj',
        method: function() {
            // this → obj
            alert(this.name);
        }
    };

    Теперь в каком бы месте мы не вызвали obj.method();, всегда будет выводится сообщение «obj».

    Методы core и $ объекта window — ссылки, указывающие на один и тот же объект. При явном вызове core(…) или $(…) в любом месте кода, сохраняют контекст (this → window), т. к. эти записи эквивалентны window.core(…) или window.$(…).

    Проверка if(this.core) return new core(arg); была введена для сокращения записи конструктора, чтобы не писать каждый раз new core(…) или new $(…). Такая рекурсия хоть и несуществнно, но снижает производительность, поэтому внутри core и при написании расширений для js-core лучше использовать постоянную ссылку core и создание новго объекта с помощью new core(…).

  11. Denis Usenko / 13.02.2009 в 14:20

    Да действительно, почему-то сразу не понял )) На первый взгляд мне показалось что надежнее было бы что то вроде «!(this instanceof core)». Но на второй все встало на свои места, спасибо за развернутый ответ ))

Оставить комментарий

480×60
480×60