callee和caller是对象的两个属性,今天就来区分一下这两个:
callee是arguments对象的一个属性,指向 arguments 对象的函数,即当前函数。
caller是函数对象的一个属性,指向调用当前函数的函数体引用。
用处
1、递归
我们可能用到一些函数调用自身,即递归。平时我们计算阶乘是用下述方法:
function factorial(x) {
return x<=1 ? 1 : x*factorial(x-1); }
运行后发现它很好的完成了我们的要求。可是还是存在一个问题,万一哪天有人重构这个函数改了函数名呢?修改不方便甚至漏改。
arguments.callee
使用callee 避免hard code 函数名。
function factorial(num) {
return num<=1 ? 1 : num * arguments.callee(num-1); }
callee是arguments对象的一个属性,指向 arguments 对象的函数,即当前函数。在例子中是factorial(num)。
caller
函数对象的一个属性,指向调用当前函数的函数。比如 A() 调用 B(), 则在B()中 B.caller 指向A()。
function B(){
console.log(B.caller); } (function A(){
B() })()
显然,只有当函数被调用时,该属性才会有值。不过当函数被全局调用时,该属性为null。
callee和caller结合
我们刚才在函数B() 中使用了 B.caller 。跟上面递归一样,将来如果有人重构改了函数名呢? 下面用刚才说的 arguments.callee 替换。
function A(){
B(); } function B(){
console.log(arguments.callee.caller); //事项更松散的耦合,访问同样的信息 } A();
到这是不是好多了。再执行A() ,发现跟刚才的输出一样。
但是在严格模式下运行时,访问arguments.callee会导致错误,在非严格模式下始终是undefined。定义这个属性是为了分清arguments.caller和函数的caller属性。还有一个限制是不能为函数的caller属性赋值,否则会导致错误。
2、斐波那契数列
function fib(nMonth){
return nMonth<=2 ? 1 : arguments.callee(nMonth -1) + arguments.callee(nMonth - 2) } console.log(fib(10))
function fib(nMonth){
var tempResult = []; if(nMonth<=2){ return 1; } else { if(tempResult[nMonth] > 0) { return tempResult[nMonth]; } else { tempResult[nMonth] = arguments.callee(nMonth -1) + arguments.callee(nMonth - 2); return tempResult[nMonth]; } } } // 递归是从大往小分解问题,循环则是反方向算法。
3、箭头函数
我们知道 ES6 新特性中引入了箭头函数。比如:
var sum = (num1, num2) => num1 + num2; // 等同于 var sum2 = function(num1, num2) {
return num1 + num2; }; // 验证 console.assert(sum(1, 2) == 3)
现在问题来了,箭头函数中this作用域跟函数外是一致的,且没有 arguments 对象。而上面我们都是从 arguments 中获取 callee 的。因此在箭头函数中,上述使用是失效的。
var sum3 = () => console.log(arguments); // Uncaught ReferenceError: arguments is not defined
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/214308.html原文链接:https://javaforall.net
