在函数内部有着一个名叫arguments的类数组对象,内部包含着传入函数的所有参数,在arguments对象中,有一个名叫callee的属性,其作用可见下面这个阶乘的栗子:
1 | function factorial(num){ |
可以看到的是,arguments.callee这个属性作为一个指针指向了拥有arguments对象的函数,也可以认为是当前正在执行的函数,而且可以消除与函数名factorial的耦合,不过值得注意的是,在ES5的严格模式下,调用arguments.callee方法会报错。
函数内部还有一个对象,就是我们所熟悉的this对象,this对象引用的是函数执行的环境对象,简单来说,this总是指向函数的直接调用者,而非间接调用者,在对象中,如果有new关键字,this指向new出来的那个对象。
在函数对象中,有个属性名为caller,这个属性作为一个引用,保存着调用当前函数的其他函数的引用,如下
1 | (function(){ |
可以看到的是,匿名函数内部调用了bar函数,在bar函数内部,因为 bar.calller指向了调用bar的匿名函数,所以执行bar.caller就等于匿名函数的源代码,同callee一样的是,在ES5中访问caller属性会报错。
函数内部除了以上容易混淆的属性以外,还有些方法有时候也会让人比较困惑,例如call跟apply,show the code
1 | function add(a,b){ |
可以看到的是,call和apply两个方法作用都是在特定的作用域上面调用函数,换句话说,就是改变函数体内this指向,在foo和bar函数中,我们利用call和apply将函数的this值绑定到add函数上,因此它们便可以对内部的参数执行add函数里面的加法操作。
call和apply方法大作用致相同,不同的方法接受的参数,call必须要明确所有要处理的参数,也就是说,参数必须要逐个列举,而apply方法可以选择数组作为参数,因此可以在具体的环境中,看看是选择call还是apply方法。