JavaScript的caller属性和callee属性对比总结

目录

背景

  要说这两个方法,必须先说另一个东西—实参对象(arguments)。标识符arguments是指向实参对象的引用。当传入某个函数的参数个数超过函数定义时指定的形参个数时,默认的处理方法是自动忽略多出来的参数。也就是说,默认这不会引起错误。但是这会有另一个问题:无法获取多出来的参数的引用了(无法知道多出来的参数具体值是什么)。这也正是实参对象arguments可以解决的问题。通过arguments和数字下标,我们就可以获取任意某个传入的参数了。之所以能够通过数字下标,是因为arguments是一个类数组对象,有着以数字为索引的一系列属性(至于什么是类数组对象,在JavaScript的call()、apply()、bind()方法对比总结这篇文章中提到过)。除了这些属性外,正如真正的数组一样,arguments还有一个length属性,用来标识传入参数的总个数。arguments的存在,极大提高了传参的灵活性,可以使得函数扩展性更好,可操作任意数量的参数。在ECMA-262, 3rd官方文档中,对于一个函数被调用后,arguments对象的创建和初始化描述如下:

  本文要提到的caller属性和callee属性,正是和arguments对象相关两个属性。理解的时候,可以类比“employer”和“employee”这两个单词,即“雇主”和“雇员”的概念。


caller属性

  在ECMAScript5严格模式中,对此属性的读/写操作均会产生类型错误TypeError
  在非严格模式下,caller属性表示调用当前正在执行的函数的函数。如果函数是由顶层来调用,那么caller的值为null。见如下实验过程:

注意:caller是由函数来调用的,即格式为:functionName.caller,而不是arguments.caller,也就是说caller不是arguments的属性。如果写成了arguments.caller,编辑器也会给出如下警告:


callee属性

  在ECMAScript5严格模式中,对此属性的读/写操作均会产生类型错误TypeError
  在非严格模式下,callee属性表示当前正在执行的函数。如下所示:

  callee属性常用于递归操作:

  这种情况下,可以给callee()传入参数,但是在上述过程中,通过caller或者callee获取“调用正在执行的函数的函数”或者“正在执行的函数”时,是以“属性”体现的,也就是说不能在caller或者callee后面加括号,否则报如下错误:

  另外,arguments.length是实参长度,arguments.callee.length是形参长度,由此callee也可以用于判断调用时形参长度是否和实参长度一致。


说明

  在ES6中(默认就是严格模式),上述两种属性被禁用。