Автоматическое добавление console.log к каждой функции

97

Есть ли способ заставить любую функцию выводить оператор console.log при его вызове, зарегистрировав где-нибудь глобальный перехватчик (то есть, не изменяя саму функцию) или каким-либо другим способом?

JRL
источник
отличный вопрос, я хотел бы знать, возможно ли это, но я почти уверен, что это не так ... Может быть, добавить запрос функции для ее добавления в движок js для вашего любимого браузера? :-)
Endophage
Идеальный вопрос, мне нужно что-то подобное
mjimcua

Ответы:

62

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

function augment(withFn) {
    var name, fn;
    for (name in window) {
        fn = window[name];
        if (typeof fn === 'function') {
            window[name] = (function(name, fn) {
                var args = arguments;
                return function() {
                    withFn.apply(this, args);
                    return fn.apply(this, arguments);

                }
            })(name, fn);
        }
    }
}

augment(function(name, fn) {
    console.log("calling " + name);
});

С одной стороны, никакие функции, созданные после вызова, не augmentбудут иметь дополнительного поведения.

Уэйн
источник
Правильно ли он обрабатывает возвращаемые значения функции?
SunnyShah
2
@SunnyShah Нет, это не так: jsfiddle.net/Shawn/WnJQ5 Но этот: jsfiddle.net/Shawn/WnJQ5/1, хотя я не уверен, что он будет работать во ВСЕХ случаях ... Разница меняется fn.apply(this, arguments);наreturn fn.apply(this, arguments);
Shawn
2
@Shawn @SunnyShah Исправлено. Просто нужно было добавить returnк самой внутренней функции.
Уэйн
работает почти нормально, но я получаю сообщение об ошибке с помощью этого jquery: call: if (jQuery.isFunction (lSrc)), и он говорит: TypeError: jQuery.isFunction не является функцией
fekiri Malek
4
Это решение не использует jQuery
Уэйн
8

На мой взгляд, это наиболее элегантное решение:

(function() {
    var call = Function.prototype.call;
    Function.prototype.call = function() {
        console.log(this, arguments); // Here you can do whatever actions you want
        return call.apply(this, arguments);
    };
}());
Сергей Мелл
источник
7

Прокси-метод для регистрации вызовов функций

Есть новый способ использования прокси для достижения этой функциональности в JS. Предположим, что мы хотим иметь console.logкаждый раз, когда вызывается функция определенного класса:

class TestClass {
  a() {
    this.aa = 1;
  }
  b() {
    this.bb = 1;
  }
}

const foo = new TestClass()
foo.a() // nothing get logged

мы можем заменить создание нашего класса прокси, который переопределяет каждое свойство этого класса. так:

class TestClass {
  a() {
    this.aa = 1;
  }
  b() {
    this.bb = 1;
  }
}


const logger = className => {
  return new Proxy(new className(), {
    get: function(target, name, receiver) {
      if (!target.hasOwnProperty(name)) {
        if (typeof target[name] === "function") {
          console.log(
            "Calling Method : ",
            name,
            "|| on : ",
            target.constructor.name
          );
        }
        return new Proxy(target[name], this);
      }
      return Reflect.get(target, name, receiver);
    }
  });
};



const instance = logger(TestClass)

instance.a() // output: "Calling Method : a || on : TestClass"

убедитесь, что это действительно работает в Codepen


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

Кроме того, этот метод работает в Node.js тоже.

Сурена
источник
Можете ли вы сделать это без использования экземпляров и классов? Конкретно говоря в node.js?
Ревадике
@Revadike, это должно помочь: stackoverflow.com/a/28708700/5284370
Soorena
1

Если вы хотите более целенаправленное ведение журнала, следующий код будет регистрировать вызовы функций для определенного объекта. Вы даже можете изменить прототипы объектов, чтобы все новые экземпляры тоже регистрировались. Я использовал Object.getOwnPropertyNames вместо for ... in, поэтому он работает с классами ECMAScript 6, у которых нет перечислимых методов.

function inject(obj, beforeFn) {
    for (let propName of Object.getOwnPropertyNames(obj)) {
        let prop = obj[propName];
        if (Object.prototype.toString.call(prop) === '[object Function]') {
            obj[propName] = (function(fnName) {
                return function() {
                    beforeFn.call(this, fnName, arguments);
                    return prop.apply(this, arguments);
                }
            })(propName);
        }
    }
}

function logFnCall(name, args) {
    let s = name + '(';
    for (let i = 0; i < args.length; i++) {
        if (i > 0)
            s += ', ';
        s += String(args[i]);
    }
    s += ')';
    console.log(s);
}

inject(Foo.prototype, logFnCall);
Питер Ценг
источник
-1

Вот некоторый Javascript, который заменяет добавляет console.log к каждой функции в Javascript; Поиграйте с ним на Regex101 :

$re = "/function (.+)\\(.*\\)\\s*\\{/m"; 
$str = "function example(){}"; 
$subst = "$& console.log(\"$1()\");"; 
$result = preg_replace($re, $subst, $str);

Это «быстрый и грязный прием», но я считаю его полезным для отладки. Если у вас много функций, будьте осторожны, потому что это добавит много кода. Кроме того, RegEx прост и может не работать для более сложных имен / объявлений функций.

болтовня
источник
-10

Фактически вы можете прикрепить свою собственную функцию к console.log для всего, что загружается.

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}
Хенрик Альбрехтссон
источник
2
правильно или нет, это не отвечает на вопрос. вообще. (на случай, если кто-то ВСЕ ЕЩЕ запутался)
redfox05 03