主题
javascript中最有意思的就是函数,函数也是对象。本文主要讲解函数对象中的三个在属性:
- length
- arguments
- caller
1. length
没错,length
属性并非数组专有,函数也有。在函数中length
属性描述的是参数的数量,如果没有参数则长度等于0。
2. arguments
arguments
是一个类数组对象,包含着传入函数的所有参数,以及他自身的一些属性。arguments
不是一个 Array
。它类似于Array
,但除了length属性和索引元素之外没有任何Array
属性。例如,它没有 pop
方法。但是它可以被转换为一个真正的Array
:
function sum (num1, num2) {
console.log(arguments) // Arguments(2) [10, 15, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// 转化数组①
console.log([].slice.call(arguments))// [10, 15]
// 转化数组②
console.log(Array.prototype.slice.call(arguments)) // [10, 15]
// 转化数组③ es6
console.log(Array.from(arguments)) // [10, 15]
return num1 + num2
}
sum(10, 15)
复制代码
上面涉及的call
方法先理解为参数传递,会再写一篇文章来讲解。查看一下在函数内打印arguments
对象都是些啥:
arguments
对象还有一个名叫
callee
的属性,该属性其实就是一个指针,指向拥有这个
arguments
对象的函数。那么
arguments.callee()
等于
sum()
。这在函数的名称是未知时很有用,例如在没有名称的函数表达式 (也称为
匿名函数)。那
callee
这玩意有啥用呢?来看一下《
javascript高级程序设计》的描述的经典阶乘函数:
function factorial(num) {
return num <= 1 ? 1 : (num * factorial(num - 1))
}
复制代码
定义阶乘一般都需要用到递归算法,递归的时候需要明确递归的函数,这样带来的问题就是函数的执行便与函数名仅仅的耦合在了一起。为了消除这种耦合,则可以使用arguments.callee
:
function factorial(num) {
return num <= 1 ? 1 : (num * arguments.callee(num - 1))
}
复制代码
在什么情况下需要使用这种匿名函数呢?传送门
3. caller
如果一个函数f
是在全局作用域内被调用的,则f.caller
为null
,相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller
指向调用它的那个函数。
function outer () {
inner()
}
function inner () {
console.log(inner.caller)
}
outer()
复制代码
控制台:
ƒ outer () {
inner()
}
复制代码
在控制台中显示了
outer()
函数的源码。因为outer()
调用了inner()
,所以inner.caller
就指向了outer()
。为了实现更松散的耦合,也可以使用arguments.callee.caller
代替inner.caller
。
结语
本文目的在于自己的知识梳理与加强。
参考文献:
- 《javascript高级程序设计》
- MDN
种一颗树最好的时间是十年前。