1.定义函数(Defining function)
函数声明
一个函数定义(也称为函数声明,或函数语句)由一系列的函数关键字组成,依次为:
- 函数的名称
- 函数参数列表,包围在括号() 中并有逗号,隔开
- 函数功能,包围在大括号{}中,用于定义函数功能的一些JS语句
在函数调用时传入的参数,为基本数据类型是值传递,引用数据类型是引用传递。
function name([param] [, param] [..., param]) {
statements
}
函数表达式
上面的函数声明在语法上是一个语句,但函数也可以由函数表达式创建。这样的函数可以是匿名的;它不必有一个名称。
var var1 = function [name]([param] [, param] [..., param]){
statements
}
2.作用域和函数堆栈
递归
一个函数可以指向并调用自身。有三种方法可以达到:
1.函数名
2.arguments.callee
3.作用域下的一个指向该函数的变量名
事实上,递归函数就使用了堆栈:函数堆栈。
嵌套函数和闭包
你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包(closure)。一个闭包是一个可以自己拥有独立的环境与变量的的表达式(通常是函数)。
可以总结如下:
- 内部函数只可以在外部函数中访问。
- 内部函数形成了一个闭包:它可以访问外部函数的参数和变量,但是外部函数却不能使用它的参数和变量。
保存变量
一个闭包必须保存它可见作用域中所有参数和变量。因为每一次调用传入的参数都可能不同,每一次对外部函数的调用实际上重新创建了一遍这个闭包。只有当返回没有再被引用时,内存才会被释放。
命名冲突
当同一个闭包作用域下两个参数或者变量同名时,就会产生命名冲突。更近的作用域有更高的优先权,所以最近的优先级最高,最远的优先级最低。这就是作用域链。链的第一个元素就是最里面的作用域,最后一个元素便是最外层的作用域。
闭包
JavaScript允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。但是,外部函数却不能够访问定义在内部函数中的变量和函数。当内部函数生存周期大于外部函数时,由于内部函数可以访问外部函数的作用域,定义在外部函数的变量和函数的生存周期就会大于外部函数本身。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。
3.使用arguments对象
函数的实际参数会被保存在一个类似数组的arguments对象中。在函数内,你可以按如下方式找出传入的引数:
arguments[i]
使用arguments对象,你可以处理比声明的更多的参数来调用函数。这在你事先不知道会需要将多少参数传递给函数时十分有用。你可以用arguments.length来获得实际传递给函数的参数的数量,然后用arguments对象来取得每个参数。
4.函数参数
从ECMAScript 6开始,有两个新的类型的参数:默认参数(default parameters),剩余参数(rest parameters)。
默认参数
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
剩余参数
剩余参数语法允许将不确定数量的参数表示为数组。
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x); //使用了箭头函数
}
var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]