Menambahkan console.log ke setiap fungsi secara otomatis

97

Apakah ada cara untuk membuat fungsi mengeluarkan pernyataan console.log ketika dipanggil dengan mendaftarkan hook global di suatu tempat (yaitu, tanpa mengubah fungsi sebenarnya itu sendiri) atau melalui cara lain?

JRL
sumber
pertanyaan yang sangat bagus, saya ingin tahu apakah ini mungkin tetapi saya cukup yakin itu tidak ... Mungkin menambahkan permintaan fitur untuk ditambahkan di mesin js untuk browser favorit Anda? :-)
Endophage
Pertanyaan yang tepat, saya butuh sesuatu yang serupa seperti ini
mjimcua

Jawaban:

62

Berikut cara untuk menambah semua fungsi di namespace global dengan fungsi pilihan Anda:

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);
});

Satu sisi negatifnya adalah bahwa tidak ada fungsi yang dibuat setelah pemanggilan augmentakan memiliki perilaku tambahan.

Wayne
sumber
Apakah itu menangani nilai kembalian fungsi dengan benar?
SunnyShah
2
@SunnyShah Tidak tidak: jsfiddle.net/Shawn/WnJQ5 Tapi yang ini: jsfiddle.net/Shawn/WnJQ5/1 meskipun saya tidak yakin ini akan berfungsi di SEMUA kasus ... Perbedaannya adalah berubah fn.apply(this, arguments);menjadireturn fn.apply(this, arguments);
Shawn
2
@Shawn @Shah Tetap. Hanya perlu menambahkan a returnke fungsi paling dalam.
Wayne
berfungsi hampir dengan baik tetapi saya mendapatkan kesalahan dengan jquery ini: call: if (jQuery.isFunction (lSrc)) dan dikatakan: TypeError: jQuery.isFunction bukanlah sebuah fungsi
fekiri malek
4
Solusi ini tidak menggunakan jQuery
Wayne
8

Bagi saya, ini terlihat seperti solusi paling elegan:

(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);
    };
}());
Sergey Mell
sumber
7

Metode Proksi untuk mencatat panggilan Fungsi

Ada cara baru menggunakan Proxy untuk mencapai fungsi ini di JS. berasumsi bahwa kita ingin memiliki console.logfungsi kapan pun dari kelas tertentu dipanggil:

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

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

kita dapat mengganti instance kelas kita dengan Proxy yang mengganti setiap properti kelas ini. begitu:

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"

periksa apakah ini benar-benar berfungsi di Codepen


Ingatlah bahwa menggunakan Proxymemberi Anda lebih banyak fungsi daripada hanya mencatat nama konsol.

Juga metode ini berfungsi di Node.js juga.

Soorena
sumber
Dapatkah Anda juga melakukan ini tanpa menggunakan instance dan kelas? Secara khusus berbicara di node.js?
Revadike
@Revadike ini akan membantu: stackoverflow.com/a/28708700/5284370
Soorena
1

Jika Anda ingin logging lebih bertarget, kode berikut akan mencatat panggilan fungsi untuk objek tertentu. Anda bahkan dapat memodifikasi prototipe Object sehingga semua instance baru juga dapat masuk. Saya menggunakan Object.getOwnPropertyNames dan bukan untuk ... in, jadi ia bekerja dengan kelas ECMAScript 6, yang tidak memiliki metode enumerable.

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);
Peter Tseng
sumber
-1

Berikut beberapa Javascript yang menggantikan menambahkan console.log ke setiap fungsi di Javascript; Mainkan di Regex101 :

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

Ini adalah 'peretasan cepat dan kotor' tetapi menurut saya berguna untuk debugging. Jika Anda memiliki banyak fungsi, berhati-hatilah karena ini akan menambah banyak kode. Selain itu, RegEx sederhana dan mungkin tidak berfungsi untuk nama / deklarasi fungsi yang lebih kompleks.

hexicle
sumber
-10

Anda sebenarnya dapat melampirkan fungsi Anda sendiri ke console.log untuk semua yang dimuat.

console.log = function(msg) {
    // Add whatever you want here
    alert(msg); 
}
Henrik Albrechtsson
sumber
2
benar atau tidak, itu tidak menjawab pertanyaan itu. sama sekali. (jika ada yang MASIH bingung)
redfox05