• 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

  • 相关阅读:
    04.日志管理
    刷爆美国朋友圈的超燃短片:年轻人为什么要奋斗?
    【逗比作孽呀】网站缓存优化
    来看看这20个顶尖的开源项目!
    nginx处理问题笔记
    -bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
    一个创业公司倒下的128小时
    快速打造跨平台开发环境 vagrant + virtualbox + box
    【Git 使用笔记】第四部分:git在公司中的开发流程
    新购买的vps应该做的几件事情
  • 原文地址:https://www.cnblogs.com/fudashi/p/6380129.html
Copyright © 2020-2023  润新知