本文内容:javascript
今天看了javascript函数的相关知识,果真平时用多了各类框架,对于原生js的掌握并没那么深刻,每次看都有新的收获,本篇文章和你们分享对于函数名和函数参数的理解,以及为何JS中没有函数重载的概念。html
函数名是指向函数对象的指针
首先要知道Javascript中的函数实际上也是对象,每一个函数都是Function类型的实例而已。由于是对象,因此函数名其实和包含对象指针的其余变量没有什么区别,也是一个指向函数对象的指针。java
var obj = {} function a () { console.log(1) }
如上,变量obj实际上是指向一个空对象的指针,一样函数名a与变量obj并没什么不一样,也是指向此函数对象的一个指针。
**再次强调一遍,函数名仅仅是指向函数对象的指针!**
那么下面的例子就能够很好的理解了:数组
function a (num1, num2) { return num1 + num2 } var b = a alert(b(1,1)) // 2 a = null alert(b(1,1)) // 2
以上代码中,首先定义了一个函数a,而后将其赋值给变量b, 由于知道了a是指向咱们所定义的函数的指针,因此这个赋值操做其实作的是将a指向的地址传递给变量b,此时b也指向了咱们定义的函数对象,那么调用b就会执行咱们定义的函数,即使接下来改变了a的指向为一个空对象,但并不影响b的指向,也就依然能正常执行函数,输出函数结果2.过程以下:浏览器
理解函数参数
javascript中的函数参数与其余语言中的函数参数有所不一样,javascript中的参数没有参数个数和类型的限制,也就是说,不管你定义的时候定义了几个参数,实际调用的时候依然能够传任意多个参数,甚至不传,更没有参数类型的限制。
之因此是这样,缘由是javascript中的在内部使用一个数组来表示的。函数内部接收到的始终是这个数组,不关心数组有哪些参数或者是否有参数。而在函数体内能够经过arguments来访问这个参数数组,获取到函数的每个参数。
arguments
只是一个相似数组的对象,但它并非Array的实例。它一样能够经过下面这种方式访问它的每个元素:arguments[0],arguments[1]...一样拥有length属性,表示函数传递进来的参数个数。闭包
function doSomething (num1, num2) { if (arguments.length > 2) { // 若是函数有两个以上的参数 console.log(arguments[2]) // 输出第三个参数 } }
arguments获取到的函数参数与对应的函数形参的同步特性
arguments有一个特殊的性质,就是它的值永远和对应的形参保持同步。
举个例子就明白了,若是一个函数的参数有三个,实际调用的时候只传了两个参数,那么前两个arguments元素与形参保持同步,即共享数据而且改变时保持同步,而第三个形参与arguments[2]是不一样步的。app
function fn (a, b, c) { console.log(a === arguments[0]) // true a = {name: 'zhangsan', age: 18} console.log(arguments[0]) // {name: 'zhangsan', age: 18} console.log(b === arguments[1]) // true arguments[1] = {name: 'lisi'} console.log(b) // {name: 'lisi'} c = 40 console.log(arguments[2]) // undefined arguments[2] = '123' console.log(c) // 40, 可见c与arguments[2]是互不影响的 } var p1 = {name: 'xiaoming', age: 6} var p2 = {age: 10} fn(p1, p2)
**注意:没被传递参数的形参和相应的arguments元素都被赋值为undefined,就像是定义了变量,但没有被初始化同样。**
*另外,形参与对应的arguments元素保持同步,并不表明他们是读取相同的内存空间,它们的内存空间是独立的,只是值会同步而已。*框架
arguments对象三个有用属性:length、callee、properties-indexes函数
arguments.callee应用以下:性能
function fn(n) { if (n <= 1) { return 1 } else { return n * arguments.callee(n - 1) // arguments.callee指向当前函数的引用,这里至关因而在递归调用fn() } } console.log(5) // 20
虽然使用arguments.callee消除了函数的执行与函数名的紧密耦合,不论函数名怎么改变,这里都能正确递归调用此函数。可是访问arguments是一个很是昂贵的操做,由于arguments是一个很大的对象,每次递归时都须要从新建立。影响现代浏览器的性能,还会影响闭包,因此arguments.callee并不同意使用。
将arguments对象转为数组
有两种方法能够将arguments对象转为数组:
到这里对函数参数和函数名作了这些了解后,咱们就能够深刻理解下为何javascript中没有函数重载了。请看下篇文章:
[深刻理解为何javascript没有函数重载](http://www.javashuo.com/article/p-xdklqlig-cy.html)