Показать сообщение отдельно
  #1 (permalink)  
Старый 26.11.2014, 02:52
Кандидат Javascript-наук
Отправить личное сообщение для SunnyDay Посмотреть профиль Найти все сообщения от SunnyDay
 
Регистрация: 22.09.2008
Сообщений: 111

Магия с 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)?

Последний раз редактировалось SunnyDay, 26.11.2014 в 02:58.
Ответить с цитированием