2009-09-27 3 views
14

Объекты jQuery действуют как массивы без загрязнения собственных прототипов. Как это достигается?Как объекты jQuery имитируют массивы?

Я знаю, что это не просто объекты с цифровыми клавишами - так что, возможно, это вопрос предоставления соответствующих методов (что-то вроде jQuery.prototype.indexOf = Array.prototype.indexOf).

Я googled и посмотрел на источник, но не смог найти окончательного ответа.

+3

Что заставляет вас поверить, что это не просто объекты с цифровыми клавишами? – Marius

+2

С одной стороны, Firebug отображает объекты jQuery как массивы, но не такие созданные вручную объекты - и я сомневаюсь, что у него есть специальная обработка для jQuery. – AnC

ответ

26

Хотя объекты jQuery действуют как массивы, они на самом деле только array-like объектов. Объект, подобный массиву, представляет собой объект с использованием цифровых клавиш и имеющий свойство length - это минимум, необходимый для совместимости с native array methods.

Поскольку объекты JQuery только массив типа, а не фактические объекты Array, родные операции массива (как indexOf или reverse) не может быть вызван непосредственно. Вы можете использовать Array.prototype, или расширить функциональность jQuery.

$('div').reverse(); // TypeError: $("div").reverse is not a function 

// we can use Array.prototype though 
Array.prototype.reverse.apply($('div')); 

// or we can extend jQuery very easily 
$.fn.reverse = Array.prototype.reverse; 
$('div').reverse(); // now it works! 

Вы правильно в своем предположении, что Firebug не содержит каких-либо специальных кожухотрубные для форматирования объектов JQuery. Быстрый поиск показывает a relevant post в списке рассылки Firebug. Предполагая, что информация по-прежнему правильная (сообщение с января) Firebug будет форматировать объект как массив, если он имеет конечной длины и splice метод.

JQuery выполняет оба этих критерия, но their implementation of splice является не чем иным, как прямой копией родного метода Array. Он недокументирован, что означает, что он либо предназначен только для внутреннего использования, либо, возможно, добавлен исключительно для цели использования Firebug в форматировании объектов jQuery.

+0

Это отлично - спасибо! Я бы сговорился добавить метод сплайсинга, чтобы он выглядел красиво в Firebug, но это всего лишь небольшая деталь. (PS: В вашем посте есть опечатка, вы упоминаете «срез» вместо «сращивания».) – AnC

+0

Спасибо - исправлено. Я только предполагаю, что метод 'splice' был добавлен в jQuery специально для Firebug, потому что ветвь 1.2 jQuery не создает такой метод. Действительно, я помню короткий период времени, когда объекты jQuery не форматировались как «Массивы» в Firebug. Конечно, введение метода в 1.3 может иметь просто совпадение. –

+1

Спасибо - это было интересно на случай. Я отмечаю, что веб-инспектор Safari, похоже, использует те же критерии - объект 'length' и метод' splice' - для форматирования объектов в виде массивов: 'var o; o = {length: 2, splice: function (x) {}}; '=>' [] '(tho 'firebug строго печатает:' [undefined, undefined] '). –

5

Посмотрите в Jquery код (разработка), строка 139:

// Force the current matched set of elements to become 
// the specified array of elements (destroying the stack in the process) 
// You should use pushStack() in order to do this, but maintain the stack 
setArray: function(elems) { 
    // Resetting the length to 0, then using the native Array push 
    // is a super-fast way to populate an object with array-like properties 
    this.length = 0; 
    Array.prototype.push.apply(this, elems); 
     return this; 
}, 

Это потому, что любой результат Jquery запросов является массивом.

+0

Спасибо. Я тоже это видел, но этого, похоже, недостаточно: var MyObj = function (args) { this.length = 0; Array.prototype.push.apply (это, аргументы); верните это; }; var obj = new MyObj («привет», «мир»); – AnC

+1

Не возвращайте 'this' из конструктора! Кроме того, 'var' устанавливает переменную, но не возвращает значение; если вы выполняете этот фрагмент в инструменте, подобном Firebug: «var MyObj = function (args) {this.length = 0; Array.prototype.push.apply (это, аргументы); }; obj = new MyObj («hello», «world»); ' –

+0

Я запутался: если это не конструктор,« это »не будет объектом (просто окно), хотя !? Можете ли вы предоставить рабочий образец? – AnC

Смежные вопросы