การเพิ่ม console.log ให้กับทุกฟังก์ชันโดยอัตโนมัติ


97

มีวิธีที่จะทำให้ฟังก์ชันใด ๆ ส่งออกคำสั่ง console.log เมื่อถูกเรียกใช้โดยการลงทะเบียน global hook ที่ใดที่หนึ่ง (นั่นคือโดยไม่ต้องแก้ไขฟังก์ชันจริง) หรือด้วยวิธีการอื่น ๆ ?


คำถามที่ยอดเยี่ยมฉันอยากทราบว่าเป็นไปได้หรือไม่ แต่ฉันค่อนข้างแน่ใจว่าไม่ใช่ ... อาจจะเพิ่มคำขอคุณสมบัติเพื่อเพิ่มในเอ็นจิ้น 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 คง. จำเป็นต้องเพิ่ม a returnในฟังก์ชันด้านในสุด
Wayne

ใช้งานได้ดี แต่ฉันได้รับข้อผิดพลาดกับ jquery นี้: โทร: if (jQuery.isFunction (lSrc)) และระบุว่า: TypeError: jQuery.isFunction ไม่ใช่ฟังก์ชัน
fekiri malek

4
โซลูชันนี้ไม่ใช้ jQuery
Wayne

10

สำหรับฉันนี่ดูเหมือนวิธีแก้ปัญหาที่หรูหราที่สุด:

(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

วิธีพร็อกซีเพื่อบันทึกการเรียกใช้ฟังก์ชัน

มีวิธีใหม่ในการใช้Proxyเพื่อให้บรรลุฟังก์ชันนี้ใน 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

@Revadike สิ่งนี้น่าจะช่วยได้: stackoverflow.com/a/28708700/5284370
Soorena

1

หากคุณต้องการบันทึกที่ตรงเป้าหมายมากขึ้นรหัสต่อไปนี้จะบันทึกฟังก์ชันการเรียกใช้สำหรับวัตถุเฉพาะ คุณยังสามารถปรับเปลี่ยนต้นแบบวัตถุเพื่อให้อินสแตนซ์ใหม่ทั้งหมดได้รับการบันทึกด้วย ฉันใช้ Object.getOwnPropertyNames แทนสำหรับ ... ในดังนั้นจึงทำงานกับคลาส 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.