Function之caller
前言
函数的调用关系,谁调用了谁,我是谁,你清楚吗?
除了Error的stack获取信息外,你还知道哪些手段知道了?
今天就一起学习学习caller和callee这两个属性。
caller
获取指定函数的调用者。
在浏览器控制台,执行下面的代码:
function sum(num1, num2) { console.log("caller:",sum.caller); return num1 + num2; } sum(1, 2); // caller: null function doSum() { sum(1, 2) } doSum(); // caller: ƒ doSum() { // sum(1, 2) // } 复制代码
可以看到全局作用域下,返回的是null,反之是调用该函数的函数。
在nodejs(v12.14.1)环境下执行 node [文件名].js
, 返回值如下:
// caller: [Function] // caller: [Function: doSum] 复制代码
我们稍微调整一下代码, 把输出的信息调整为sum.caller.toString()
;
function sum(num1, num2) { console.log("caller:",sum.caller.toString()); return num1 + num2; } sum(1, 2); // 输出结果: /* caller: function (exports, require, module, __filename, __dirname) { function sum(num1, num2) { console.log("caller:",sum.caller.toString()); return num1 + num2; } sum(1, 2); function doSum() { sum(1, 2) } doSum() } */ function doSum() { sum(1, 2) } doSum() // 输出结果 /* caller: function doSum() { sum(1, 2) } */ 复制代码
可以看到使用node [文件名].js
执行js文件的时候,最终被包裹成如下函数
function (exports, require, module, __filename, __dirname) { // 省略代码 } 复制代码
严格模式的caller
修改sum函数为下面的代码,再执行代码:
function sum(num1, num2) { "use strict"; console.log("caller:",sum.caller.toString()); return num1 + num2; } 复制代码
可以看到,严格模式下, caller
, callee
, arguments
属性都是不可用的。
平时大家都使用了严格模式吗? 其实很多库,都还在使用arguments
参数,因为实在是太香,太方便了。
caller的用途
跟踪调用信息
可以用于跟踪函数的调用层级关系,是不是很秀?
function getStack(fn) { const stacks = []; let caller = fn.caller; while (caller) { stacks.unshift(caller.name); caller = caller.caller; } return stacks; } function a() { console.log("a") const stacks = getStack(a); console.log("stacks:", stacks); } function b() { a(); console.log("b"); } function c() { b(); console.log("c") } c(); // stacks: (2) ['c', 'b'] 复制代码
检查被调用环境
function getCaller(fun) { const caller = fun.caller; if (caller == null) { console.log("caller is global context"); } else{ console.log("caller.name:" + caller); } return fun.caller } function add(){ getCaller(add) } add() // caller is global context 复制代码
小结
一句话总结: caller, 谁调用了我?
注意点:
严格模式下,不可用
全局作用域内被调用,caller为null
用途:
调用环境检查
调用栈信息收集
这就对应了前言的话,除了Error能获取调用栈信息, caller也不失为一种取巧的获取方式,当然有一定的局限性,又何妨,特定场景有作用,就够了。
今天你收获了吗?
作者:一花一个世界
链接:https://juejin.cn/post/7017679608807948318