簡體   English   中英

通過函數調用JavaScript獲取對象調用者名稱

[英]Get object caller name by function call JavaScript

我正在編寫一段代碼,以輕松將錯誤日志保存在對象中以進行調試。

我想要實現的是從調用它的函數中獲取對象名稱,如下所示:

var MainObject = {
    test : function() {
        return MainObject.test.caller;
        // When called from MainObject.testcaller,
        // it should return MainObject.testcaller.
    },

    testcaller : function() {
       return MainObject.test(); // Should return MainObject.testcaller, Returns own function code.
    },

    anothercaller : function() {
       return MainObject.test(); // Should return MainObject.anothercaller, Returns own function code.
    }
}

但是,當我運行此代碼時,它將從MainObject.testcaller返回功能代碼。

JSFiddle示例

有什么辦法可行嗎?

更新資料

查看Rhumborl的答案后,我發現通過另一個函數分配值將導致它指向沒有對象本身的函數名稱。

碼:

(function (name, func) {
    MainObject[name] = func;
})('invalid', function() {
    return MainObject.test("blah"); 
}); 

// This now points at invalid() rather than MainObject.invalid()

更新的小提琴

函數有一個非標准的調用者屬性 ,該屬性返回調用者函數,但是它是指向函數對象的指針,並且不會告訴您作為方法的對象或對象名稱。 您可以通過arguments.callee獲得對該函數的引用。

還有過時的arguments.caller ,但不要使用它。 它還提供了對調用函數的引用(如果支持)。

一旦有了對調用函數的引用(如果有的話),就會遇到解析其名稱的問題。 假設函數是對象,並且對象可以由多個屬性和變量引用,則具有特定名稱的函數的概念是泛濫的。

但是,如果您知道該函數是某個對象的屬性,則可以遍歷該對象自己的可枚舉屬性以找出它是哪個。

但這似乎是一件很奇怪的事情。 您實際上想做什么? 您可能正在嘗試以更健壯和更簡單的方式解決問題。

編輯

您可以使用上述針對OP中情況的方法以非常有限的方式來執行所需的操作,但是這種方法不可靠,也不是通用的解決方案:

var mainObject = {
    test : function() {
      var obj = this;
      var caller = arguments.callee.caller;
      var global = (function(){return this}());
      var fnName, objName;

      for (var p in global) {
        if (global[p] === obj) {
          objName = p;
        }
      }

      for (var f in obj) {
        if (obj[f] === caller) {
          fnName = f;
        }
      }

      return objName + '.' + fnName;
    },

    testcaller : function() {
       return mainObject.test();
    },

    anothercaller : function() {
       return mainObject.test();
    }
}


console.log(mainObject.testcaller());    // mainObject.testcaller
console.log(mainObject.anothercaller()); // mainObject.anothercaller

但它很脆弱:

var a = mainObject.anothercaller;
console.log(a()); // mainObject.anothercaller    

var b = {
  foo : mainObject.anothercaller
}

console.log(b.foo()); // mainObject.anothercaller

哎呀。

您可以在http://www.eriwen.com/javascript/js-stack-trace/上使用此技巧,該技巧將引發錯誤,然后解析堆棧跟蹤。

我已將其更新為Firefox,Chrome和IE的最新版本。 不幸的是,它在我的IE9上無法正常運行(並且我還沒有在Opera上對其進行測試)。

 function getStackTrace() { var callstack = []; var isCallstackPopulated = false; try { i.dont.exist += 0; //doesn't exist- that's the point } catch (e) { if (e.stack) { //Firefox/Chrome/IE11 var lines = e.stack.split('\\n'); for (var i = 0, len = lines.length; i < len; i++) { var line = lines[i].trim(); if (line.match(/^at [A-Za-z0-9\\.\\-_\\$]+\\s*\\(/)) { // Chrome/IE: " at Object.MainObject.testcaller (url:line:char)" var entry = line.substring(3, line.indexOf('(') - 1); // Chrome appends "Object." to the front of the object functions, so strip it off if (entry.indexOf("Object.") == 0) { entry = entry.substr(7, entry.length); } callstack.push(entry); } else if (line.match(/^[A-Za-z0-9\\.\\-_\\$]+\\s*@/)) { // Firefox: "MainObject.testcaller@url:line:char" callstack.push(line.substring(0, lines[i].indexOf('@'))); } } //Remove call to getStackTrace() callstack.shift(); isCallstackPopulated = true; } else if (window.opera && e.message) { //Opera var lines = e.message.split('\\n'); for (var i = 0, len = lines.length; i < len; i++) { if (lines[i].match(/^\\s*[A-Za-z0-9\\-_\\$]+\\(/)) { var entry = lines[i]; //Append next line also since it has the file info if (lines[i + 1]) { entry += lines[i + 1]; i++; } callstack.push(entry); } } //Remove call to getStackTrace() callstack.shift(); isCallstackPopulated = true; } } if (!isCallstackPopulated) { //IE9 and Safari var currentFunction = arguments.callee.caller; while (currentFunction) { var fn = currentFunction.toString(); var fname = fn.substring(fn.indexOf("function") + 8, fn.indexOf('')) || 'anonymous'; callstack.push(fname); currentFunction = currentFunction.caller; } } return callstack; } var MainObject = { test: function (x) { // first entry is the current function (test), second entry is the caller var stackTrace = getStackTrace(); var caller = stackTrace[1]; return caller + "()"; }, testcaller: function () { return MainObject.test(1, null); } } function SomeFunction() { return MainObject.test("blah"); } document.body.innerHTML += '<b style="color: red">' + MainObject.testcaller() + '</b>'; document.body.innerHTML += '<div>Calling SomeFunction() returns: <b style="color: red">' + SomeFunction() + '</b></div>'; 
 MainObject.test() should return: <b style="color: blue">MainObject.testcaller()</b> <hr /> MainObject.test() returns: 

在這里更新小提琴

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM