function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Çağrı yığınını bulmanın bir yolu var mı?
function main()
{
Hello();
}
function Hello()
{
// How do you find out the caller function is 'main'?
}
Çağrı yığınını bulmanın bir yolu var mı?
Yanıtlar:
function Hello()
{
alert("caller is " + Hello.caller);
}
Bu özellik olduğuna dikkat edin standart dışı gelen, Function.caller
:
Standart
dışı Bu özellik standart değildir ve standartlar üzerinde değildir. Web'e bakan üretim sitelerinde kullanmayın: her kullanıcı için çalışmaz. Uygulamalar arasında büyük uyumsuzluklar olabilir ve gelecekte davranışlar değişebilir.
Aşağıdaki, modern Javascript'te artık desteklenmeyen 2008'den gelen eski cevaptır:
function Hello()
{
alert("caller is " + arguments.callee.caller.toString());
}
arguments.callee.caller.name
işlevin adını alır.
'use strict';
yardımcı olabilir.
arguments
Katı modda bir işlev içinden erişilebilir, bunu reddetmek aptalca olacaktır. sadece fonksiyondan değil. dışarıdan argümanlar. Ayrıca, adlandırılmış bir bağımsız değişkeniniz varsa, bunun [i] biçimindeki bağımsız değişkenler, işlev içindeki adlandırılmış sürümde yaptığınız değişiklikleri izlemez.
Tarayıcıya özel kodu kullanarak yığın izlemenin tamamını bulabilirsiniz. İyi olan, birisinin zaten yapmış olması ; İşte GitHub'daki proje kodu .
Ancak tüm haberler iyi değil:
Yığın izini almak gerçekten yavaştır, bu yüzden dikkatli olun ( daha fazla bilgi için bunu okuyun ).
Yığın izinin okunabilir olması için işlev adlarını tanımlamanız gerekir. Çünkü böyle bir kodunuz varsa:
var Klass = function kls() {
this.Hello = function() { alert(printStackTrace().join('\n\n')); };
}
new Klass().Hello();
Google Chrome uyarı verir, ... kls.Hello ( ...
ancak çoğu tarayıcı anahtar kelimeden hemen sonra bir işlev adı bekler function
ve bunu anonim bir işlev olarak görür. Bir işlev bile Klass
adını vermezseniz , Chrome bile adı kullanamaz kls
.
Ve bu arada, printStackTrace işlevine geçebilirsiniz, {guess: true}
ancak bunu yaparak gerçek bir gelişme bulamadım.
Tüm tarayıcılar size aynı bilgileri vermez. Yani, parametreler, kod sütunu vb.
Bu arada, yalnızca arayan işlevinin adını istiyorsanız (çoğu tarayıcıda, ancak IE'de değil) kullanabilirsiniz:
arguments.callee.caller.name
Ancak, bu adın function
anahtar kelimeden sonraki ad olacağını unutmayın . Tüm fonksiyonun kodunu almadan daha fazlasını elde etmenin bir yolunu (Google Chrome'da bile) bulamadım.
Ve en iyi cevapların geri kalanını özetlemek (Pablo Cabrera, nourdine ve Greg Hewgill tarafından). Kullanabileceğiniz tek çapraz tarayıcı ve gerçekten güvenli olan şey:
arguments.callee.caller.toString();
Arayan fonksiyonunun kodunu gösterecektir . Ne yazık ki, bu benim için yeterli değil ve bu yüzden size StackTrace ve arayan işlev Adı (çapraz tarayıcı olmasa da) için ipuçları veriyorum.
Function.caller
Ancak katı modda çalışmaz.
"Javascript'te" bahsettiğinizi biliyorum, ancak amaç hata ayıklamaksa, tarayıcınızın geliştirici araçlarını kullanmanın daha kolay olduğunu düşünüyorum. Chrome'da şu şekilde görünür: Hata ayıklayıcıyı yığını araştırmak istediğiniz yere bırakın.
Tekrar özetlemek (ve netleştirmek için) ...
bu kod:
function Hello() {
alert("caller is " + arguments.callee.caller.toString());
}
buna eşdeğerdir:
function Hello() {
alert("caller is " + Hello.caller.toString());
}
Açıkçası ilk bit daha taşınabilir, çünkü fonksiyonun adını değiştirebilir, "Merhaba" dan "Ciao" ya da her şeyi çalıştırabilirsiniz.
İkincisinde, çağrılan işlevin adını (Merhaba) yeniden düzenlemeye karar verirseniz, tüm oluşumlarını değiştirmeniz gerekir :(
Tüm yığın izini alabilirsiniz:
arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller
Arayana kadar null
.
Not: özyinelemeli işlevlerde sonsuz bir döngüye neden olur.
Genellikle (new Error()).stack
Chrome'da kullanırım . Güzel olan şey, aynı zamanda arayanın işlevi çağırdığı satır numaralarını da vermesidir. Dezavantajı, yığının uzunluğunu 10 ile sınırlamasıdır, bu yüzden bu sayfaya ilk etapta geldim.
(Bunu, yürütme sırasında düşük düzeyli bir kurucuda çağrı stoklarını toplamak, daha sonra görüntülemek ve hata ayıklamak için kullanıyorum, bu yüzden bir kesme noktası ayarlamak binlerce kez vurulacağı için kullanılmıyor)
'use strict';
. Bana ihtiyacım olan bilgiyi verdi - teşekkürler!
IE <11'de çalıştırmayacaksanız console.trace () uygun olacaktır.
function main() {
Hello();
}
function Hello() {
console.trace()
}
main()
// Hello @ VM261:9
// main @ VM261:4
Arama işlevini almak için Function.Caller öğesini kullanabilirsiniz. Argument.caller kullanan eski yöntem eski sayılır.
Aşağıdaki kod kullanımını göstermektedir:
function Hello() { return Hello.caller;}
Hello2 = function NamedFunc() { return NamedFunc.caller; };
function main()
{
Hello(); //both return main()
Hello2();
}
Eski argüman.caller hakkında notlar: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller
Function.caller'ın standart dışı olduğunu unutmayın: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
Cannot access caller property of a strict mode function
Bunu yapardım:
function Hello() {
console.trace();
}
function Hello() {
alert(Hello.caller);
}
arguments.callee.caller.toString()
Kullanımı güvenlidir *arguments.callee.caller
beri arguments.caller
olduğu kaldırılmış ...
arguments.callee
ES5'te de kullanımdan kaldırıldı ve katı modda kaldırıldı.
arguments.callee
şimdi daha iyi çözülmüş bir soruna kötü bir çözüm geliştirici.mozilla.org/
Bu oldukça çözülmüş bir soru gibi görünüyor ama son zamanlarda callee 'katı modda' izin verilmediğini öğrendim, bu yüzden kendi kullanımım için çağrıldığı yerden alacak bir sınıf yazdım. It adlı küçük bir yardımcı lib parçası ve (1 yerine 2 kullanımı) arayanın yığın izlemesini döndürmek için kullanılan ofset kod bağımsız değişikliğini kullanmak istiyorsanız
function ScriptPath() {
var scriptPath = '';
try {
//Throw an error to generate a stack trace
throw new Error();
}
catch(e) {
//Split the stack trace into each line
var stackLines = e.stack.split('\n');
var callerIndex = 0;
//Now walk though each line until we find a path reference
for(var i in stackLines){
if(!stackLines[i].match(/http[s]?:\/\//)) continue;
//We skipped all the lines with out an http so we now have a script reference
//This one is the class constructor, the next is the getScriptPath() call
//The one after that is the user code requesting the path info (so offset by 2)
callerIndex = Number(i) + 2;
break;
}
//Now parse the string for each section we want to return
pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
}
this.fullPath = function() {
return pathParts[1];
};
this.path = function() {
return pathParts[2];
};
this.file = function() {
return pathParts[3];
};
this.fileNoExt = function() {
var parts = this.file().split('.');
parts.length = parts.length != 1 ? parts.length - 1 : 1;
return parts.join('.');
};
}
function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()
Konsolda benim için çalışmıyor (bir dosyada denemedim), ancak makul bir fikir var gibi görünüyor. Görünürlük için yine de kaldırılmalıdır.
Buna erişmeyi deneyin:
arguments.callee.caller.name
Sadece hata yığını konsol günlüğü. Daha sonra nasıl arandığını öğrenebilirsin
const hello = () => {
console.log(new Error('I was called').stack)
}
const sello = () => {
hello()
}
sello()
Hem ES6 hem de Katı modda, Arayan işlevini almak için aşağıdakileri kullanın
console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])
Arayan veya önceki yığın yoksa yukarıdaki satırın bir istisna atacağını lütfen unutmayın. Uygun şekilde kullanın.
console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
caller
katı modda yasaktır . İşte (standart olmayan) Error
yığını kullanan bir alternatif .
Aşağıdaki işlev, Firefox 52 ve Chrome 61-71'de işi yapıyor gibi görünse de, uygulaması iki tarayıcının günlük biçimi hakkında çok sayıda varsayım yapar ve bir istisna fırlatması ve muhtemelen iki normal ifadeyi yürütmesi durumunda dikkatli kullanılmalıdır. yapılmadan önce eşleşmeler.
'use strict';
const fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;
function fnName(str) {
const regexResult = fnNameMatcher.exec(str);
return regexResult[1] || regexResult[2];
}
function log(...messages) {
const logLines = (new Error().stack).split('\n');
const callerName = fnName(logLines[1]);
if (callerName !== null) {
if (callerName !== 'log') {
console.log(callerName, 'called log with:', ...messages);
} else {
console.log(fnName(logLines[2]), 'called log with:', ...messages);
}
} else {
console.log(...messages);
}
}
function foo() {
log('hi', 'there');
}
(function main() {
foo();
}());
Bunun için kemanımı buraya eklemek istedim:
http://jsfiddle.net/bladnman/EhUm3/
Bunun krom, safari ve IE (10 ve 8) olduğunu test ettim. İyi çalışıyor. Önemli olan sadece 1 fonksiyon var, bu yüzden büyük kemandan korkarsanız, aşağıda okuyun.
Not: Bu kemanda adil bir miktarda kendi "kazan plakam" var. Bunların hepsini kaldırabilir ve isterseniz split'leri kullanabilirsiniz. Bu sadece güvendiğim ultra güvenli bir dizi işlev.
Orada da bir "JSFiddle" şablonu var ben sadece hızlı kemanlık için birçok keman için kullandığım.
String.prototype.trim = trim;
Kodun yerine fonksiyonun adını ve tarayıcıdan bağımsız bir çözüm istiyorsanız, aşağıdakileri kullanın:
var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];
Dizide [1] öğesi olmadığından, arayan işlevi yoksa yukarıdakilerin bir hata döndüreceğini unutmayın. Geçici çözüm bulmak için aşağıdakileri kullanın:
var callerFunction = (arguments.callee.caller.toString().match(/function ([^\(]+)/) === null) ? 'Document Object Model': arguments.callee.caller.toString().match(/function ([^\(]+)/)[1], arguments.callee.toString().match(/function ([^\(]+)/)[1]);
Sadece o bildirmek istiyorum PhoneGap / Androidname
doesnt çalışıyor gibi görünüyor. Ama arguments.callee.caller.toString()
hile yapacak.
Burada, RegExp ile her şey functionname
soyulur caller.toString()
.
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Show the callers name</title><!-- This validates as html5! -->
<script>
main();
function main() { Hello(); }
function Hello(){
var name = Hello.caller.toString().replace(/\s\([^#]+$|^[^\s]+\s/g,'');
name = name.replace(/\s/g,'');
if ( typeof window[name] !== 'function' )
alert ("sorry, the type of "+name+" is "+ typeof window[name]);
else
alert ("The name of the "+typeof window[name]+" that called is "+name);
}
</script>
İşte tam yığın izleme almak için bir fonksiyon :
function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
stack += '\n' + f.name;
f = f.caller;
}
return stack;
}
heystewart'ın yanıtı ve JiarongWu'nun yanıtı , Error
nesnenin nesneye erişimi olduğunu belirtti stack
.
İşte bir örnek:
function main() {
Hello();
}
function Hello() {
var stack;
try {
throw new Error();
} catch (e) {
stack = e.stack;
}
// N.B. stack === "Error\n at Hello ...\n at main ... \n...."
var m = stack.match(/.*?Hello.*?\n(.*?)\n/);
if (m) {
var caller_name = m[1];
console.log("Caller is:", caller_name)
}
}
main();
Farklı tarayıcılar yığını farklı dize biçimlerinde gösterir:
Safari : Caller is: main@https://stacksnippets.net/js:14:8
Firefox : Caller is: main@https://stacksnippets.net/js:14:3
Chrome : Caller is: at main (https://stacksnippets.net/js:14:3)
IE Edge : Caller is: at main (https://stacksnippets.net/js:14:3)
IE : Caller is: at main (https://stacksnippets.net/js:14:3)
Çoğu tarayıcı yığını var stack = (new Error()).stack
. Internet Explorer'da yığın tanımsız olacaktır - yığını almak için gerçek bir istisna atmanız gerekir.
Sonuç: "ana" belirlemek mümkündür kullanarak "Hello" ile arayan olduğu stack
içinde Error
nesne. Aslında callee
/ caller
yaklaşımının çalışmadığı durumlarda işe yarar. Ayrıca bağlam, yani kaynak dosya ve satır numarası gösterilecektir. Ancak, çözümü çapraz platform haline getirmek için çaba sarf etmek gerekir.
Node.js'de Function.caller'ı kullanamazsınız , bunun yerine caller-id paketini kullanabilirsiniz . Örneğin:
var callerId = require('caller-id');
function foo() {
bar();
}
function bar() {
var caller = callerId.getData();
/*
caller = {
typeName: 'Object',
functionName: 'foo',
filePath: '/path/of/this/file.js',
lineNumber: 5,
topLevelFlag: true,
nativeFlag: false,
evalFlag: false
}
*/
}
Aşağıdaki kodu deneyin:
function getStackTrace(){
var f = arguments.callee;
var ret = [];
var item = {};
var iter = 0;
while ( f = f.caller ){
// Initialize
item = {
name: f.name || null,
args: [], // Empty array = no arguments passed
callback: f
};
// Function arguments
if ( f.arguments ){
for ( iter = 0; iter<f.arguments.length; iter++ ){
item.args[iter] = f.arguments[iter];
}
} else {
item.args = null; // null = argument listing not supported
}
ret.push( item );
}
return ret;
}
Firefox-21 ve Chromium-25'te benim için çalıştı.
arguments.callee
yıllardır kullanımdan kaldırıldı .
Bu soruna bir başka yol, parametre olarak çağrı işlevinin adını iletmektir.
Örneğin:
function reformatString(string, callerName) {
if (callerName === "uid") {
string = string.toUpperCase();
}
return string;
}
Şimdi, işlevi şu şekilde çağırabilirsiniz:
function uid(){
var myString = "apples";
reformatString(myString, function.name);
}
Örneğim, işlev adının sabit kodlu bir denetimini kullanıyor, ancak orada istediğinizi yapmak için kolayca bir switch deyimi veya başka bir mantık kullanabilirsiniz.
Bildiğim kadarıyla bunun gibi kaynaklardan bunun için 2 yolumuz var.
function whoCalled()
{
if (arguments.caller == null)
console.log('I was called from the global scope.');
else
console.log(arguments.caller + ' called me!');
}
function myFunc()
{
if (myFunc.caller == null) {
return 'The function was called from the top!';
}
else
{
return 'This function\'s caller was ' + myFunc.caller;
}
}
Sanırım cevabınız var :).
Neden yukarıdaki tüm çözümler bir roket bilimi gibi görünüyor. Bu arada, bu pasajdan daha karmaşık olmamalıdır. Bu adama verilen tüm krediler
JavaScript'te arayan işlevini nasıl öğrenirsiniz?
var stackTrace = function() {
var calls = [];
var caller = arguments.callee.caller;
for (var k = 0; k < 10; k++) {
if (caller) {
calls.push(caller);
caller = caller.caller;
}
}
return calls;
};
// when I call this inside specific method I see list of references to source method, obviously, I can add toString() to each call to see only function's content
// [function(), function(data), function(res), function(l), function(a, c), x(a, b, c, d), function(c, e)]
Bu soruyu hem soruyu hem de mevcut ödülü ele almaya çalışıyorum.
Ödül, arayanın katı modda elde edilmesini gerektirir ve bunu yapmanın tek yolu katı mod dışında bildirilen bir işleve başvurmaktır .
Örneğin, aşağıdakiler standart değildir ancak Chrome, Edge ve Firefox'un önceki (29/03/2016) ve mevcut (1 Ağustos 2018) sürümleriyle test edilmiştir.
function caller()
{
return caller.caller.caller;
}
'use strict';
function main()
{
// Original question:
Hello();
// Bounty question:
(function() { console.log('Anonymous function called by ' + caller().name); })();
}
function Hello()
{
// How do you find out the caller function is 'main'?
console.log('Hello called by ' + caller().name);
}
main();
Gerçekten herhangi bir nedenden dolayı işlevselliğe ihtiyacınız varsa ve tarayıcılar arası uyumlu olmasını ve sıkı şeyler için endişelenmemenizi ve ileriye uyumlu olmasını istiyorsanız, bu referansı iletin:
function main()
{
Hello(this);
}
function Hello(caller)
{
// caller will be the object that called Hello. boom like that...
// you can add an undefined check code if the function Hello
// will be called without parameters from somewhere else
}
Aşağıdaki kod parçası yararlı olabilir düşünüyorum:
window.fnPureLog = function(sStatement, anyVariable) {
if (arguments.length < 1) {
throw new Error('Arguments sStatement and anyVariable are expected');
}
if (typeof sStatement !== 'string') {
throw new Error('The type of sStatement is not match, please use string');
}
var oCallStackTrack = new Error();
console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}
Kodu yürütün:
window.fnPureLog = function(sStatement, anyVariable) {
if (arguments.length < 1) {
throw new Error('Arguments sStatement and anyVariable are expected');
}
if (typeof sStatement !== 'string') {
throw new Error('The type of sStatement is not match, please use string');
}
var oCallStackTrack = new Error();
console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}
function fnBsnCallStack1() {
fnPureLog('Stock Count', 100)
}
function fnBsnCallStack2() {
fnBsnCallStack1()
}
fnBsnCallStack2();
Günlük şöyle görünür:
Call Stack:
at window.fnPureLog (<anonymous>:8:27)
at fnBsnCallStack1 (<anonymous>:13:5)
at fnBsnCallStack2 (<anonymous>:17:5)
at <anonymous>:20:1
Stock Count: 100