1、概述
- 函数声明
- 采用函数表达式声明函数时,function命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。
var print = function x(){ console.log(typeof x); }; x // ReferenceError: x is not defined
-
- 这种写法的用处有两个,一是可以在函数体内部调用自身,二是方便除错。
- 函数名提升
- JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。
- 如果像下面例子那样,采用function命令和var赋值语句声明同一个函数,由于存在函数提升,最后会采用var赋值语句的定义。
var f = function () { console.log(‘1‘); } function f() { console.log(‘2‘); } f() // 1
2、函数的属性和方法
- length属性
- 函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。
function f(a, b) {} f.length // 2 // 上面代码定义了空函数f,它的length属性就是定义时的参数个数。不管调用时输入了多少个参数,length属性始终等于2。 // length属性提供了一种机制,判断定义时和调用时参数的差异,以便实现面向对象编程的“方法重载”(overload)。
- toString()
- 函数的toString()方法返回一个字符串,内容是函数的源码。
3、函数作用域
- 定义
- 作用域(scope)指的是变量存在的范围。在 ES5 的规范中,JavaScript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。ES6 又新增了块级作用域。
- 注意,对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。
- 函数内部变量提升
- 与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。
- 函数本身作用域
- 函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关(词法作用域)。
var a = 1; var x = function () { console.log(a); }; function f() { var a = 2; x(); } f() // 1
4、参数
- 参数的省略
- 函数参数不是必需的,JavaScript 允许省略参数。
function f(a, b) { return a; } f(1, 2, 3) // 1 f(1) // 1 f() // undefined f.length // 2 // 没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。
- 传递方式
- 函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。
var p = 2; function f(p) { p = 3; } f(p); p // 2 // 上面代码中,变量p是一个原始类型的值,传入函数f的方式是传值传递。因此,在函数内部,p的值是原始值的拷贝,无论怎么修改,都不会影响到原始值。
-
- 如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。
var obj = { p: 1 }; function f(o) { o.p = 2; } f(obj); obj.p // 2
-
- 如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。
var obj = [1, 2, 3]; function f(o) { o = [2, 3, 4]; } f(obj); obj // [1, 2, 3] // 这是因为,形式参数(o)的值实际是参数obj的地址,重新对o赋值导致o指向另一个地址,保存在原地址上的值当然不受影响。
- 同名参数
- 如果有同名的参数,则取最后出现的那个值;即使后面的a没有值或被省略,也是以其为准。
function f(a, a) { console.log(a); } f(1, 2) // 2 function f(a, a) { console.log(a); } f(1) // undefined
- arguments对象
- 定义
- 正常模式下,arguments对象可以在运行时修改。
- 严格模式下,arguments对象与函数参数不具有联动关系。也就是说,修改arguments对象不会影响到实际的函数参数。
- 与数组的关系
- 它是类似数组的对象,可转换为数组。
- 定义