zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    剑指offer——包含min函数的栈
    剑指offer——顺时针打印矩阵
    剑指offer——二叉树的镜像
    剑指offer——树的子结构
    爬虫的单线程+多任务异步协程:asyncio 3.6
    爬虫中的模拟登陆,IP代理,线程池
    爬虫-数据解析
    爬虫基础
    Markdown语法
    Git
  • 原文地址:https://www.cnblogs.com/fudashi/p/6380129.html
Copyright © 2011-2022 走看看