Магия с JS Proxy
При разработке фреймворка для XUL-UI (для Firefox плагинов) - встал вопрос о том, чтобы представлять элемент(там это чекбокс, селект, групбокс например) и группу тех-же элементов (массив тобишь) одним и тем же интерфейсом. При том что все элементы хоть и наследуются от от одного базового, но имеют разные прототипы(классы). То есть должны работать простые примеры:
element.attr('class','some');//устанавливает класс одного элемента в some [element1, element2, element3].attr('class','some');//устанавливает класс 3-х элементов в some //метода val - например нет в базовом классе этого фреймворка, потому что не все имеют значения - логично вроде element.val();//возвращает значение элемента [element1, element2, element3].val();//возвращает массив, каждый элемент которого соответствует значению каждого элемента в исходном массиве [element1, element2].find('.some').attr('atr','atrVal');//в 2-х элементах находим все дочерние элементы с классом some и присваиваем им некий аттрибут Заворачивать в один класс работу как со множеством, так и с одним элементов( как делает jQuery) - было бы накладно по архитектуре, и грозило бы потерей гибкости. Но оставлять как в mootools - аля забудь про множества, тоже неприемлемо. Очень быстро нагуглилось классное решение вопроса - Proxy https://developer.mozilla.org/en-US/..._Objects/Proxy . Создал обёрточный метод который при попытке вызова любого метода множества - вызывает его у каждого элемента множества, и формирует резутат-массив, каждый элемент которого соответствует результату вызванного множества: //функция-проксер, проксирующая массив var Multiplicity = function(in_array){ var proxy = new Proxy(in_array,{ get: function(target, name) { if (name in target) return target[name]; var proxyMethod = function(){ var proxyResult = []; for(var i=0;i<target.length;i++){ if (!target[i]) continue; if (typeof target[i][name] == 'function'){ proxyResult.push(target[i][name].apply(target[i], arguments)); }else if (typeof target[i][name] != 'undefined'){ proxyResult.push(target[i][name]); }else{ proxyResult.push(undefined); } } return Multiplicity(proxyResult); } return proxyMethod; } }); return proxy; }; //ПРИМЕР использования проксера массивов var cls = function(){ this.f = function(){return new subCls();}; }; var subCls = function(){ this.f2 = function(){return Math.random();}; }; Multiplicity([new cls(), new cls()]).f().f2();//выведет массив из двух случайных чисел Multiplicity([new cls(), new subCls()]).f2();//выведет [undefined, случайное_число] подход нравится своей волшебной гибкостью(с первого взгляда) - какие бы программисты не дописали методы в классы элементов, Proxy будет их "есть". Но вот вопрос, нет ли в таком подходе подводных камней, да таких что могут потопить UI-фреймворк? Есть ли причины не использовать Proxy кроме того что объект пока по-умолчанию доступен только в Firefox (а в остальных браузерах пока в стадии experimental)? |
мое скромное мнение
![]() |
:write:
мне вот тут понравилось как одиночный элемент превращается в массив, да и сама обработка каждого элемента ... http://javascript.ru/forum/misc/5188...tml#post342783 |
-не вот тут понравилось как одиночный элемент превращается в массив
так как там превращается - это стандартно, и везде используется. Но для случая - когда ко множеству нужно применить последовательно несколько методов в которых могут быть аргументы - так просто не получится. Вот пример jQuery: jQuery('.red').find.('div').find('a').css('color','red'); Нужно чтобы работало так-же. Только с той разницей что в jQuery фиксированный класс элемента - не используется наследование, вместо этого плагинизация базового класса. Требуется же использовать наследование, да так что множеству(массиву состоящему возможно из элементов разных классов) можно так-же вызвать через точку методы, описанные хотя-бы в одном элементе множества. Вобщем да, Proxy - пошло в разработку уже, решили его юзать :) |
рони, кстати, вместо
isset(o, ['a', 'w', 'r', 't', 'y']) можно по-человечески использовать typeof o.a.w.r.t.y если o наследник Proxy. А так - как делает функция isset вышеприведённая, портит стилистику и читаемость кода. Правка. нет - вру, typeof - не получится, но просто вместо эксепшена o.a.w.r.t.y может возвращить null например , если o - Proxy . |
Цитата:
var cls = function() { } cls.prototype.f = function() { return new subCls(); } |
Цитата:
|
Для информации - с JS-Proxy имеется всё-таки один подводный камень: это производительность. Видимо оптимизаторы пока его ещё не так лихо едят. Поясню - если завернуть массив в Proxy и переопределить get (как в примере топика), то в нём сразу же в огромные разы медленнее начинают работать вшитые методы, особенно indexOf . Поэтому не стоит это использовать Proxy больших массивов. Но для небольших массивов, которые не крутятся рекурсивно по 10 раз - самое то)
|
Часовой пояс GMT +3, время: 07:16. |