ФорумПрограммированиеПыхнуть хотите?Готовые решения → Перехватчик вызовов методов

Перехватчик вызовов методов

  • vasa_c

    Сообщения: 3131 Репутация: N Группа: в ухо

    Spritz 1 ноября 2007 г. 12:28

    [size=12]Перехватчик вызовов методов[/size]

    Немного извращений…
    Не в качестве даже готового решения, а просто как подсказка забавной фишки.

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

    var eventsCallMethod = new (function()
    {

    this.attach = (
    function(obj, methodName, handler, before)
    {
    var id = handlers.length;
    var h = {
    "obj" : obj,
    "method" : methodName,
    "old" : obj[methodName],
    "handler": handler,
    "before" : before
    }
    obj[methodName] = (
    function()
    {
    if (before) {
    var ret = h.old.apply(obj, arguments);
    handler.apply(obj, arguments);
    return ret;
    }
    if (!handler.apply(obj, arguments)) {
    return;
    }
    return h.old.apply(obj, arguments);
    });
    handlers[id] = h;
    return id;
    });

    this.dettach = (
    function(id)
    {
    var h = handlers[id];
    if (h) {
    h.obj[h.method] = h.old;
    handlers[id] = false;
    }
    return true;
    });


    var handlers = [];

    })();


    Позволяет перехватывать события вызовов методов каких-либо объектов.

    Пример номер раз:

    <script type="text/javascript" src="evmethods.js"></script>

    <div id="console"><b>Console:</b></div>
    <script type="text/javascript">

    function cWrite(text, color) {
    if (!color) {
    color = "black";
    }
    var d = document.createElement("div");
    d.appendChild(document.createTextNode(text));
    d.style.color = color;
    document.getElementById("console").appendChild(d);
    }

    var obj = {
    "name": "Йа обжегд",

    "func": (
    function()
    {
    cWrite("Йа метод объекта " + this.name);
    })
    };

    cWrite("Вызываем obj.func()", "#999999");
    obj.func();

    cWrite("Вешаем обработчик и снова вызываем obj.func()", "#999999");
    var hID = eventsCallMethod.attach(
    obj,
    "func",
    (function()
    {
    cWrite("А йа обработчег. Выполняюсь в контексте объекта " + this.name + ". Сейчас спрошу, стоит ли продолжать выполнение метода");
    var ret = confirm("Продолжим выполнение исходного метода?");
    cWrite((ret ? "Продолжение подтверждено" : "Продолжение отменено"), "#999999");
    return ret;
    })
    );
    obj.func();

    cWrite("Удалим обработчик и вызовем снова", "#999999");
    eventsCallMethod.dettach(hID);
    obj.func();

    </script>


    Есть объект obj, а у него метод func(). Нам нужно отследить все его вызовы.
    Ставим обработчик следующим образом:
    eventsCallMethod.attach(<объект>, <имя его метода>, <обработчик>)

    При вызове obj.func вызовется наш обработчик в контексте объекта obj со всеми аргументами переданными в obj.func().
    Если он возвращает true, то после него будет вызван изначальный метод. Если false, то этот вызов будет отменен.

    Четвертым аргументом attach() можно указать true, тогда вызов метода будет происходить перед вызовом обработчика. Как, надеюсь, понятно, отменить исходный метод в этом случае не получится.

    attach() возвращает идентификатор обработчика. С его помощью обработчик можно отменить:
    eventsCallMethod.dettach(id)


    Перехватывать методы можно не только у пользовательских объектов, но и у встроенных. Например, можно в некоторой мере сэмулировать обработку событий изменений DOM-дерева (из неподдерживаемого еще DOM3).


    <script type="text/javascript" src="evmethods.js"></script>

    <div id="console"><b>Console:</b></div>

    <div id="div1">1.</div>
    <div id="div2">2.</div>

    <script type="text/javascript">

    function cWrite(text, color) {
    if (!color) {
    color = "black";
    }
    var d = document.createElement("div");
    d.appendChild(document.createTextNode(text));
    d.style.color = color;
    document.getElementById("console").appendChild(d);
    }


    eventsCallMethod.attach(document.getElementById("div1"), "appendChild",
    (function(textNode) {
    cWrite('Перехватили добавление текста "' + textNode.nodeValue + '" в слой с ID="' + this.getAttribute("id") + '"');
    return true;
    })
    );

    eventsCallMethod.attach(document.getElementById("div2"), "appendChild",
    (function(textNode) {
    cWrite('Перехватили добавление текста "' + textNode.nodeValue + '" в слой с ID="' + this.getAttribute("id") + '", добавим и от себя');
    textNode.nodeValue += "(а это вам довесок от нас)";
    return true;
    })
    );

    document.getElementById("div1").appendChild(document.createTextNode("Текст номер раз"));
    document.getElementById("div2").appendChild(document.createTextNode("Текст номер два"));

    </script>


    Здесь, как видно, не просто перехватываем вставку нодов, но и можем в обработчике изменить их.

Пожалуйста, авторизуйтесь, чтобы написать комментарий!