Function.caller、arguments.caller、argument.callee

caller、callee是与javascript函数相关的两个属性,今天来总结下。

Function.caller

caller是javascript函数的一个属性,它指向调用当前函数的函数,如果函数是在全局范围内调用的话,那么caller的值为null。

function outer() {
    inner();
}
function inner() {
    if(inner.caller==null) { //值为null,在全局作用域下调用
        console.log("我是在全局环境下调用的");
    } else {
        console.log(inner.caller+"调用了我");
    }    
}
inner();
outer();

arguments.callee

arguments是函数内部中一个特殊的对象,callee是arguments的属性之一, 他指向拥有该arguments的函数对象。在某些不方便暴露函数名的情况下, 可以用arguments.callee代替函数名。但是,在严格模式(“use strict;”)下访问arguments.callee会抛出 TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them 错误

现在我们来仔细看看上面那段代码。如果老板说:“不行,函数名叫inner不好听,给我改!” 改代码容易,但是想改了后不出错误那可就难了。 这时我们就可以使用argument.callee来代替函数名,减少修改代码的地方,从而降低出错率

function outer() {
    inner();
}
function inner() { //只需改这个函数名,而不需要改内部代码
    if(arguments.callee.caller==null) {
        console.log("我是在全局环境下调用的");
    } else {
        console.log(arguments.callee.caller+"调用了我");
    }    
}
inner();
outer();

除此之外,当我们写递归函数时,也会在函数里面暴露函数名,此时也会产生问题,如下。

/**
 * factorial:阶乘
 */
function factorial(n) {
    if(n<=1) {
        return 1;
    } else {
        return n*factorial(n-1);
    }
}
console.log(factorial(3)); //6
var foo = factorial;
console.log(foo(3)); //6
factorial = null; 
console.log(foo(3)); //Error:factorial is not a function

factorial置为null,虽然foo指向了factorial使其不会被销毁, 但是原函数内部的函数名任然是factorial,自然应找不到而报错。 此时我们就可以用arguments.callee代替函数名

function factorial(n) {
    if(n<=1) {
        return 1;
    } else {
        return n*arguments.callee(n-1);
    }
}

那还能不能更强点?毕竟arguments.callee在严格模式下是无法访问的,肯定没法儿用啊!

var factorial = (function foo(n) {
    if(n<=1) {
        return 1;
    } else {
        return n*foo(n-1); //内部可访问foo
    }
});
foo(6); //ReferenceError: foo is not defined

以上代码利用命名函数表达式的形式创建了一个递归函数。 这有两个好处:第一,严格模式下函数任然能照常运转; 第二,性能优于argument.callee。注意foo仅在其函数体内可访问,在外是访问不到的。

arguments.caller

arguments.caller 这是我们遇到的第二个caller,没啥用,在严格模式下无法访问,非严格模式下值也为undefined,而且貌似被废弃了

总结

1.Function.caller指向调用该函数的函数

2.arguments.callee指向拥有该arguments的函数

3.arguments.caller没啥用

引用

1.《javascript高级程序设计》

2.MDN

  2.1 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/caller

  2.2 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

  2.3 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments/callee

posted @ 2017-02-08 22:23  付大石  阅读(4678)  评论(0编辑  收藏  举报