Làm thế nào để bạn tìm ra chức năng người gọi trong JavaScript?


866
function main()
{
   Hello();
}

function Hello()
{
  // How do you find out the caller function is 'main'?
}

Có cách nào để tìm ra ngăn xếp cuộc gọi?


63
Tôi hy vọng điều này chỉ để hỗ trợ bạn trong việc gỡ lỗi. Hành vi khác nhau dựa trên người gọi là một ý tưởng tồi.
OJ.

Khi nào thì điều này sẽ hữu ích cho việc gỡ lỗi?
Anderson Green

33
@AndersonGreen khi bạn có, ví dụ, một phương thức kết xuất mẫu mặc định và thấy nó được gọi hai lần. Thay vì kết hợp với 1000 LoC hoặc bước qua khó khăn với trình gỡ lỗi, bạn có thể thấy ngăn xếp lúc đó là gì.
tkone

28
để xem dấu vết ngăn xếp, hãy sử dụng console.trace () cho chrome. không biết về người khác mặc dù
lukas.pukenis

5
Tại sao đây là một ý tưởng tồi?
Jacob Schneider

Câu trả lời:


995
function Hello()
{
    alert("caller is " + Hello.caller);
}

Lưu ý rằng tính năng này không chuẩn , từ Function.caller:

Phi tiêu chuẩn
Tính năng này không chuẩn và không theo dõi tiêu chuẩn. Không sử dụng nó trên các trang web sản xuất phải đối mặt với Web: nó sẽ không hoạt động cho mọi người dùng. Cũng có thể có sự không tương thích lớn giữa việc thực hiện và hành vi có thể thay đổi trong tương lai.


Sau đây là câu trả lời cũ từ năm 2008, không còn được hỗ trợ trong Javascript hiện đại:

function Hello()
{
    alert("caller is " + arguments.callee.caller.toString());
}

254
arguments.callee.caller.namesẽ nhận được tên của chức năng.
Tên lửa Hazmat

137
Các thuộc tính "'người gọi', 'callee' và 'đối số' có thể không được truy cập trên các chức năng chế độ nghiêm ngặt hoặc các đối tượng đối số cho các cuộc gọi đến chúng" - chúng không được chấp nhận trong ES5 và bị xóa trong chế độ nghiêm ngặt.
ThatGuy

12
Nó sẽ chỉ hoạt động, nếu bạn không sử dụng chế độ nghiêm ngặt. Vì vậy, loại bỏ 'use strict';có thể giúp đỡ.
pvorb

23
argumentsCÓ THỂ được truy cập từ bên trong một chức năng trong chế độ nghiêm ngặt, sẽ thật ngu ngốc nếu không tán thành điều đó. chỉ không từ function.argument từ bên ngoài. Ngoài ra, nếu bạn có một đối số được đặt tên, dạng đối số [i] của nó sẽ không theo dõi các thay đổi bạn thực hiện đối với phiên bản được đặt tên bên trong hàm.
rvr_jon

41
Phương pháp này đã trở nên lỗi thời kể từ khi bài đăng này được liệt kê vào năm 2011. Phương thức ưa thích hiện nay là Function.caller, (tính đến năm 2015).
Greg

152

StackTrace

Bạn có thể tìm thấy toàn bộ dấu vết ngăn xếp bằng mã cụ thể của trình duyệt. Điều tốt là ai đó đã thực hiện nó ; đây là mã dự án trên GitHub .

Nhưng không phải tất cả các tin tức đều tốt:

  1. Thực sự rất chậm để có được dấu vết ngăn xếp vì vậy hãy cẩn thận (đọc phần này để biết thêm).

  2. Bạn sẽ cần xác định tên hàm cho dấu vết ngăn xếp dễ đọc. Bởi vì nếu bạn có mã như thế này:

    var Klass = function kls() {
       this.Hello = function() { alert(printStackTrace().join('\n\n')); };
    }
    new Klass().Hello();

    Google Chrome sẽ cảnh báo ... kls.Hello ( ...nhưng hầu hết các trình duyệt sẽ mong đợi một tên hàm ngay sau từ khóa functionvà sẽ coi nó là một hàm ẩn danh. Thậm chí Chrome sẽ không thể sử dụng Klasstên nếu bạn không đặt tên klscho chức năng.

    Và nhân tiện, bạn có thể chuyển đến hàm printStackTrace tùy chọn {guess: true}nhưng tôi không tìm thấy bất kỳ cải tiến thực sự nào bằng cách làm điều đó.

  3. Không phải tất cả các trình duyệt cung cấp cho bạn cùng một thông tin. Đó là, tham số, cột mã, v.v.


Tên người gọi

Nhân tiện, nếu bạn chỉ muốn tên của chức năng người gọi (trong hầu hết các trình duyệt, nhưng không phải IE), bạn có thể sử dụng:

arguments.callee.caller.name

Nhưng lưu ý rằng tên này sẽ là tên sau functiontừ khóa. Tôi không tìm thấy cách nào (ngay cả trên Google Chrome) để nhận được nhiều hơn thế mà không nhận được mã của toàn bộ chức năng.


Mã chức năng người gọi

Và tóm tắt phần còn lại của các câu trả lời hay nhất (của Pablo Cabrera, nourdine và Greg Hewgill). Điều duy nhất trên trình duyệt chéo và thực sự an toàn bạn có thể sử dụng là:

arguments.callee.caller.toString();

Mà sẽ hiển thị của chức năng người gọi. Đáng buồn thay, điều đó là không đủ đối với tôi và đó là lý do tại sao tôi cung cấp cho bạn các mẹo cho StackTrace và tên người gọi chức năng (mặc dù chúng không phải là trình duyệt chéo).


1
có lẽ bạn nên thêm Function.callermỗi @ câu trả lời của Greg
Zach Lysobey

Function.callerTuy nhiên, sẽ không làm việc trong chế độ nghiêm ngặt.
Rickard Elimää

54

Tôi biết bạn đã đề cập "trong Javascript", nhưng nếu mục đích là gỡ lỗi, tôi nghĩ việc sử dụng các công cụ phát triển trình duyệt của bạn sẽ dễ dàng hơn. Đây là giao diện của Chrome: nhập mô tả hình ảnh ở đây Chỉ cần thả trình gỡ lỗi nơi bạn muốn điều tra ngăn xếp.


3
Đây là một câu hỏi cũ ... nhưng đây chắc chắn là cách hiện đại nhất để làm việc này.
markstewie

53

Để tóm tắt (và làm cho nó rõ ràng hơn) ...

mã này:

function Hello() {
    alert("caller is " + arguments.callee.caller.toString());
}

tương đương với điều này:

function Hello() {
    alert("caller is " + Hello.caller.toString());
}

Rõ ràng bit đầu tiên dễ mang theo hơn, vì bạn có thể thay đổi tên của hàm, nói từ "Xin chào" thành "Ciao", và vẫn có thể làm cho toàn bộ hoạt động.

Trong trường hợp sau, trong trường hợp bạn quyết định cấu trúc lại tên của hàm được gọi (Xin chào), bạn sẽ phải thay đổi tất cả các lần xuất hiện của nó :(


7
argument.callee.caller luôn null trên Chrome 25.0.1364.5 dev
Kokizzu

53

Bạn có thể nhận được stacktrace đầy đủ:

arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller

Cho đến khi người gọi là null.

Lưu ý: nó gây ra một vòng lặp vô hạn trên các hàm đệ quy.


2
Xin lỗi vì đã trả lời trễ nhưng tôi chưa thấy bình luận của bạn trước đó; chỉ đối với trường hợp đệ quy nó không hoạt động, trong các trường hợp khác nó sẽ hoạt động.
ale5000

45

Tôi thường sử dụng (new Error()).stacktrong Chrome. Điều tuyệt vời là điều này cũng cung cấp cho bạn các số dòng nơi người gọi gọi hàm. Nhược điểm là nó giới hạn độ dài của ngăn xếp xuống còn 10, đó là lý do tại sao tôi đến trang này ngay từ đầu.

.


Bạn có thể vui lòng thêm một chút mô tả về lời giải thích bạn cung cấp?
abarisone

6
Đây là điều duy nhất tôi có thể làm việc khi 'use strict';có mặt. Đã cho tôi thông tin tôi cần - cảm ơn!
Jeremy Harris

4
Về giới hạn chiều dài ngăn xếp ... bạn có thể thay đổi điều đó với "Error.stackTraceLimit = Infinity".
Tom

(Lỗi mới ("StackLog")). stack.split ("\ n") giúp đọc dễ dàng hơn.
Teoman shipahi

36

Nếu bạn không chạy nó trong IE <11 thì console.trace () sẽ phù hợp.

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

main()
// Hello @ VM261:9
// main @ VM261:4

Nó đang hoạt động! Nên được thêm nhiều phiếu bầu
Krunal Panchal

22

Bạn có thể sử dụng Function.Caller để nhận chức năng gọi điện. Phương thức cũ sử dụng argument.caller được coi là lỗi thời.

Đoạn mã sau minh họa việc sử dụng nó:

function Hello() { return Hello.caller;}

Hello2 = function NamedFunc() { return NamedFunc.caller; };

function main()
{
   Hello();  //both return main()
   Hello2();
}

Ghi chú về đối số lỗi thời.caller: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Fiances/argument/caller

Lưu ý rằng Function.caller không chuẩn: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller


1
Đây là câu trả lời đúng trong những ngày này. Bạn không thể làm công cụ argument.caller.callee nữa. Ước gì chúng ta có thể khiến điều này được chuyển lên đầu vì tất cả những thứ khác đã lỗi thời.
coblr

4
Có vẻ như điều này là không thể trong chế độ nghiêm ngặt? Cannot access caller property of a strict mode function
Zach Lysobey

Function.caller cũng không hoạt động với tôi trong chế độ nghiêm ngặt. Ngoài ra, theo MDN , function.caller là không chuẩn và không nên được sử dụng trong sản xuất. Nó có thể làm việc để gỡ lỗi, mặc dù.
jkdev

Tôi không gặp vấn đề gì với phi tiêu chuẩn nếu nó hoạt động trong Node, nhưng đơn giản là nó không được phép ở chế độ nghiêm ngặt (tôi đã thử nghiệm trên nút 6.10). Áp dụng tương tự cho 'đối số'. Tôi nhận được thông báo errror: '' 'người gọi' và 'đối số' là các thuộc tính chức năng bị hạn chế và không thể truy cập trong ngữ cảnh này. "
Tom

21

Tôi sẽ làm điều này:

function Hello() {
  console.trace();
}

Điều này đang làm việc tuyệt vời! nên được chấp nhận là câu trả lời đúng, vì những cách khác đã cũ \ không hoạt động nữa
Yuval Pruss

19
function Hello() {
    alert(Hello.caller);
}

1
Và chỉ với tên hàm sử dụng Hello.caller.name
vanval

giống nhưarguments.callee.caller.toString()
dùng2720864

Đây phải là câu trả lời chính xác, ít nhất là cho năm 2016
Daniel

Đây không phải là một ca khúc tiêu chuẩn, nhưng sẽ hoạt động kể từ ECMAScript 5.
Obinna Nwakwue


18

Đó là an toàn hơn để sử dụng *arguments.callee.callerkể từ khi arguments.callerđược tán thành ...


36
arguments.calleecũng không được chấp nhận trong ES5 và bị xóa trong chế độ nghiêm ngặt.
nyuszika7h

2
Có một sự thay thế? Chỉnh sửa: arguments.calleelà một giải pháp tồi cho một vấn đề hiện đã được nhà phát triển
Matthew

16

Có vẻ như đây là một câu hỏi đã được giải quyết nhưng gần đây tôi phát hiện ra rằng callee không được phép ở 'chế độ nghiêm ngặt', vì vậy với mục đích sử dụng của riêng tôi, tôi đã viết một lớp sẽ lấy đường dẫn từ nơi nó được gọi. Đó là một phần của lib trợ giúp nhỏ và nếu bạn muốn sử dụng mã độc lập, hãy thay đổi phần bù được sử dụng để trả về dấu vết ngăn xếp của người gọi (sử dụng 1 thay vì 2)

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('.');
  };
}

Không hoạt động với tôi function a(){ function b(){ function c(){ return ScriptPath(); } return c(); } return b(); } a()trong bảng điều khiển (chưa thử trong tệp), nhưng dường như có một ý tưởng hợp lý. Dù sao cũng nên nâng cấp cho tầm nhìn.
ninjagecko

Ý tưởng thật tuyệt vời. Tôi phân tích cú pháp khác nhau nhưng trong các ứng dụng nw.js, đây thực sự là ý tưởng duy nhất mang lại những gì tôi đang tìm kiếm.
Andrew Grothe

Vui lòng cung cấp một ví dụ về cách gọi chức năng này.
pd_au


11

Chỉ cần bàn điều khiển đăng nhập ngăn xếp lỗi của bạn. Sau đó bạn có thể biết bạn được gọi như thế nào

const hello = () => {
  console.log(new Error('I was called').stack)
}

const sello = () => {
  hello()
}

sello()


10

Trong cả chế độ ES6 và Strict, hãy sử dụng cách sau để nhận chức năng Người gọi

console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])

Xin lưu ý rằng, dòng trên sẽ ném một ngoại lệ, nếu không có người gọi hoặc không có ngăn xếp trước đó. Sử dụng cho phù hợp.


Để lấy callee (tên hàm hiện tại), hãy sử dụng: console.log((new Error()).stack.split("\n")[1].trim().split(" ")[1])
VanagaS

10

Cập nhật 2018

callerbị cấm trong chế độ nghiêm ngặt . Đây là một thay thế bằng cách sử dụng Errorngăn xếp (không chuẩn) .

Chức năng sau đây dường như thực hiện công việc trong Firefox 52 và Chrome 61-71 mặc dù việc triển khai của nó đưa ra rất nhiều giả định về định dạng ghi nhật ký của hai trình duyệt và nên được sử dụng một cách thận trọng, vì nó ném ngoại lệ và có thể thực thi hai regex trận đấu trước khi được thực hiện.

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


4
Điều đó thật phi thường, và cũng thật kinh khủng.
Ian

Tôi nhận được "foo được gọi với: hi there", nhưng foo không được gọi với "hi there", log được gọi với "hi there"
AndrewR

Đúng, có một "sửa đổi không đúng chỗ" trong ngữ pháp của thông báo lỗi. Nó có nghĩa là "nhật ký được gọi từ hàm f, nó muốn thông báo X được in" nhưng theo cách ngắn gọn nhất có thể.
Rovmate

7

Tôi muốn thêm fiddle của tôi ở đây cho điều này:

http://jsfiddle.net/bladnman/EhUm3/

Tôi đã thử nghiệm đây là chrome, safari và IE (10 và 8). Hoạt động tốt. Chỉ có 1 chức năng quan trọng, vì vậy nếu bạn cảm thấy sợ hãi bởi câu đố lớn, hãy đọc phần bên dưới.

Lưu ý: Có một số lượng khá lớn "nồi hơi" của riêng tôi trong câu đố này. Bạn có thể loại bỏ tất cả những thứ đó và sử dụng split nếu bạn muốn. Đây chỉ là một bộ chức năng cực kỳ an toàn mà tôi tin tưởng.

Ngoài ra còn có một mẫu "JSFiddle" trong đó tôi sử dụng cho nhiều câu đố để đơn giản là nhanh chóng.


Tôi tự hỏi nếu bạn có thể thêm "người trợ giúp" làm tiện ích mở rộng cho nguyên mẫu trong một số trường hợp, ví dụ:String.prototype.trim = trim;
tự kỷ

6

Nếu bạn chỉ muốn tên hàm chứ không phải mã và muốn một giải pháp độc lập với trình duyệt, hãy sử dụng như sau:

var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];

Lưu ý rằng ở trên sẽ trả về một lỗi nếu không có chức năng người gọi vì không có phần tử [1] trong mảng. Để làm việc xung quanh, sử dụng như sau:

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

1

5

Chỉ muốn cho bạn biết rằng trên PhoneGap / Android các namedoesnt dường như làm việc. Nhưng arguments.callee.caller.toString()sẽ làm được mẹo.


4

Ở đây, mọi thứ trừ cái functionnamebị tước khỏi caller.toString(), với RegExp.

<!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>

điều này vẫn trả về toàn bộ khai báo phương thức
Maslow

4

Đây là một chức năng để có được stacktrace đầy đủ :

function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
  stack += '\n' + f.name;
  f = f.caller;
}
return stack;
}

3

Câu trả lời của heystewartcâu trả lời của JiarongWu đều đề cập rằng Errorđối tượng có quyền truy cập vào stack.

Đây là một ví dụ:

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

Các trình duyệt khác nhau hiển thị ngăn xếp trong các định dạng chuỗi khác nhau:

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)

Hầu hết các trình duyệt sẽ thiết lập ngăn xếp với var stack = (new Error()).stack . Trong Internet Explorer, ngăn xếp sẽ không được xác định - bạn phải đưa ra một ngoại lệ thực sự để truy xuất ngăn xếp.

Kết luận: Có thể xác định "chính" là người gọi "Xin chào" bằng cách sử dụng stacktrong Errorđối tượng. Trong thực tế, nó sẽ hoạt động trong trường hợp callee/ callerphương pháp không hoạt động. Nó cũng sẽ hiển thị cho bạn ngữ cảnh, tức là tệp nguồn và số dòng. Tuy nhiên, nỗ lực là cần thiết để làm cho giải pháp đa nền tảng.


2

Lưu ý rằng bạn không thể sử dụng Function.caller trong Node.js, thay vào đó hãy sử dụng gói id người gọi . Ví dụ:

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
    }
    */
}

1

Hãy thử đoạn mã sau:

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

Làm việc cho tôi trong Firefox-21 và Chromium-25.


Hãy thử điều này cho các hàm đệ quy.
daniel1426

arguments.calleeđã bị phản đối trong nhiều năm .
Dan Dascalescu

1

Một cách khác để giải quyết vấn đề này là chỉ cần truyền tên của hàm gọi làm tham số.

Ví dụ:

function reformatString(string, callerName) {

    if (callerName === "uid") {
        string = string.toUpperCase();
    }

    return string;
}

Bây giờ, bạn có thể gọi hàm như thế này:

function uid(){
    var myString = "apples";

    reformatString(myString, function.name);
}

Ví dụ của tôi sử dụng kiểm tra mã hóa cứng của tên hàm, nhưng bạn có thể dễ dàng sử dụng câu lệnh chuyển đổi hoặc một số logic khác để làm những gì bạn muốn ở đó.


Tôi tin rằng điều này cũng giải quyết hầu hết các vấn đề tương thích trình duyệt. Nhưng hãy kiểm tra điều này trước khi cho rằng nó là sự thật! ( bắt đầu đổ mồ hôi )
GrayedFox

1

Theo như tôi biết, chúng tôi có 2 cách cho việc này từ các nguồn nhất định như thế này-

  1. đối số

    function whoCalled()
    {
        if (arguments.caller == null)
           console.log('I was called from the global scope.');
        else
           console.log(arguments.caller + ' called me!');
    }
  2. Chức năng

    function myFunc()
    {
       if (myFunc.caller == null) {
          return 'The function was called from the top!';
       }
       else
       {
          return 'This function\'s caller was ' + myFunc.caller;
        }
    }

Hãy nghĩ rằng bạn có câu trả lời của bạn :).


Điều này đã bị phản đối trong nhiều năm và Function.caller không hoạt động ở chế độ nghiêm ngặt.
Dan Dascalescu

1

Tại sao tất cả các giải pháp trên trông giống như một khoa học tên lửa. Trong khi đó, nó không nên phức tạp hơn đoạn trích này. Tất cả các khoản tín dụng cho anh chàng này

Làm thế nào để bạn tìm ra chức năng người gọi trong JavaScript?

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)]

3
Đây là những gì tôi nhận được khi sử dụng tính năng này: TypeError: 'người gọi', 'callee' và 'đối số' có thể không được truy cập trên các hàm chế độ nghiêm ngặt hoặc các đối tượng đối số cho các cuộc gọi đến chúng. Bất kỳ ý tưởng làm thế nào để làm việc này trong chế độ nghiêm ngặt?
hard_work_ant

1

Tôi đang cố gắng giải quyết cả câu hỏi và tiền thưởng hiện tại với câu hỏi này.

Tiền thưởng yêu cầu người gọi phải có được ở chế độ nghiêm ngặt và cách duy nhất tôi có thể thấy điều này được thực hiện là bằng cách tham khảo một chức năng được khai báo bên ngoài chế độ nghiêm ngặt.

Ví dụ: những điều sau đây là không chuẩn nhưng đã được thử nghiệm với các phiên bản trước đó (29/03/2016) và hiện tại (ngày 1 tháng 8 năm 2018) của Chrome, Edge và Firefox.

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


Hack đẹp, nhưng sẽ không hoạt động cho các mô-đun ES5, hoàn toàn ở chế độ nghiêm ngặt .
Dan Dascalescu

0

Nếu bạn thực sự cần chức năng vì một số lý do và muốn nó tương thích với nhiều trình duyệt và không phải lo lắng về những thứ nghiêm ngặt và tương thích về phía trước thì hãy chuyển qua tham chiếu này:

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
}

0

Tôi nghĩ rằng đoạn mã sau đây có thể hữu ích:

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

Thực thi mã:

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

Nhật ký trông như thế này:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.