Có cách nào để thực hiện bất kỳ hàm nào xuất ra một câu lệnh console.log khi nó được gọi bằng cách đăng ký một hook chung ở đâu đó (nghĩa là, không sửa đổi chính hàm thực tế) hoặc thông qua một số phương tiện khác không?
Có cách nào để thực hiện bất kỳ hàm nào xuất ra một câu lệnh console.log khi nó được gọi bằng cách đăng ký một hook chung ở đâu đó (nghĩa là, không sửa đổi chính hàm thực tế) hoặc thông qua một số phương tiện khác không?
Câu trả lời:
Đây là một cách để tăng cường tất cả các chức năng trong không gian tên chung với chức năng bạn chọn:
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);
});
Một mặt trái là không có hàm nào được tạo sau khi gọi augment
sẽ có hành vi bổ sung.
fn.apply(this, arguments);
đểreturn fn.apply(this, arguments);
return
vào hàm trong cùng.
Đối với tôi, đây có vẻ là giải pháp thanh lịch nhất:
(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);
};
}());
Có một cách mới sử dụng Proxy để đạt được chức năng này trong JS. giả sử rằng chúng ta muốn có một console.log
bất cứ khi nào một hàm của một lớp cụ thể được gọi:
class TestClass {
a() {
this.aa = 1;
}
b() {
this.bb = 1;
}
}
const foo = new TestClass()
foo.a() // nothing get logged
chúng ta có thể thay thế việc khởi tạo lớp của chúng ta bằng một Proxy ghi đè từng thuộc tính của lớp này. vì thế:
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"
kiểm tra xem điều này có thực sự hoạt động trong Codepen không
Hãy nhớ rằng việc sử dụng Proxy
mang lại cho bạn nhiều chức năng hơn là chỉ ghi lại tên bảng điều khiển.
Ngoài ra phương pháp này hoạt động trong Node.js quá.
Nếu bạn muốn ghi nhật ký được nhắm mục tiêu hơn, đoạn mã sau sẽ ghi nhật ký các lệnh gọi hàm cho một đối tượng cụ thể. Bạn thậm chí có thể sửa đổi nguyên mẫu Đối tượng để tất cả các phiên bản mới cũng có thể ghi nhật ký. Tôi đã sử dụng Object.getOwnPropertyNames thay vì for ... in, vì vậy nó hoạt động với các lớp ECMAScript 6, không có các phương thức có thể liệt kê.
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);
Đây là một số Javascript thay thế thêm console.log vào mọi hàm trong Javascript; Chơi với nó trên Regex101 :
$re = "/function (.+)\\(.*\\)\\s*\\{/m";
$str = "function example(){}";
$subst = "$& console.log(\"$1()\");";
$result = preg_replace($re, $subst, $str);
Đó là một 'hack nhanh chóng và bẩn thỉu' nhưng tôi thấy nó hữu ích cho việc gỡ lỗi. Nếu bạn có nhiều chức năng, hãy cẩn thận vì điều này sẽ thêm rất nhiều mã. Ngoài ra, RegEx đơn giản và có thể không hoạt động đối với các tên / khai báo hàm phức tạp hơn.
Bạn thực sự có thể đính kèm chức năng của riêng mình vào console.log cho mọi thứ tải.
console.log = function(msg) {
// Add whatever you want here
alert(msg);
}