1.4.x 函数
定义一个函数并不会执行它,只是命名了该函数并指定了调用它时要执行的操作。
函数总会返回一个值,通常由 return 语句指定。当没有 return 语句时,就会返回默认值。对于使用 new 关键字调用的构造函数,返回的默认值是 this。对于其它所有情况,返回的默认值都是 undefined。
函数调用的参数(parameters)是函数的参数(arguments),可以是值(原始值),也可以是引用(对象)。
2. 调用函数
调用函数实际上就是用指定的参数去执行指定的操作。
在调用函数的时候,它必须在作用域内,而函数声明会被提升,如下:
注:函数提升只适用于“函数声明”,并不适用于“函数表达式”定义的函数。
函数作用域就是声明它的函数。如果它是在顶层声明的,那它的作用域就是整个程序。
正常调用、递归调用(相关概念函数作用域,function scope)
函数声明(函数提升,function hoisting)
函数表达式
其他调用方法,比如在某些情况下需要:
动态调用函数
函数的参数数量不同
将函数调用的上下文设置为在运行时确定的特定对象
函数本身就是对象,相反,这些对象也有方法(函数),其中 apply()
方法可用于实现此目标。
functions are themselves objects
3. 函数作用域
在函数内定义的变量,在函数外是不能访问的。但是反过来,函数可以访问“在其定义范围内”定义的所有变量和函数。
A function can access all variables and functions (defined inside the scope) (in which it is defined).
在全局范围内定义的函数,可以访问在全局范围内定义的所有变量
在另一个函数中定义的函数,可以访问其父函数中定义的所有变量,以及父函数可以访问的任何其他变量
4. 作用域和函数栈
4.1 递归函数
函数体里的 this 关键字,并不指向当前正在执行的函数,所以必须按名称引用 Function 对象。
一个函数可以引用和调用它自己,有三种方式:
函数的名字
arguments.callee
指向函数的变量
递归函数,比如:
递归本身使用了一个栈:函数栈。
4.2 嵌套函数和闭包
我们可以将一个函数嵌套在另一个函数中。对于外部函数来说,内部的嵌套函数是私有的。
the inner function, the nested function the outer function, the containing function
嵌套函数会形成一个闭包,闭包是一个自带执行上下文(自由变量以及绑定这些变量的环境)的表达式(最常见的是函数)。 因为内部的嵌套函数是闭包,这就意味着(内部的)嵌套函数可以“继承”(外部的)包含函数的参数和变量,换句话说就是内部函数包含外部函数的作用域(scope)。
总结一下:
内部函数只能通过外部函数的语句访问
内部函数形成一个闭包:内部函数可以使用外部函数的参数和变量,而外部函数不能使用内部函数的参数和变量
嵌套函数,比如:
嵌套函数,比如:
4.3 保留变量
闭包必须保留它引用的所有参数和变量,比如上面例子中在返回 inside
的时候,是会保留 x 的。 考虑到每次调用闭包的参数可能会不同,所以每调用一次 outside
都会创建一个新的闭包。 只有当返回的闭包 inside
不再可访问时,它的内存才会被释放。
闭包的这种工作方式和在其它对象中存储引用没什么不同,只是它的存储方式更不明显些,因为闭包没有直接设置引用也没法查看引用。
4.4 多重嵌套函数
函数可以多重嵌套。比如:
函数 A 包含函数 B,函数 B 包含函数 C
此时,函数 B 和函数 C 都形成了闭包
B 形成了一个包含 A 的闭包,也就是说 B 可以访问 A 的参数和变量
C 形成了一个包含 B 的闭包,也就是说 C 可以访问 B 的参数和变量
→ C 可以访问 B 和 A 的参数和变量
我们可以看到,闭包是可以包含多个作用域(scope)的,它们递归地包含“包含它的函数”的作用域,这称为作用域链(scope chaining)。
4.5 命名冲突
当闭包作用域内的两个参数或变量具有相同的名称时,就会发生命名冲突。 嵌套的越深,优先级就越高。 也就是说,最内部的作用域具有最高优先级,最外部的作用域具有最低优先级,这就是作用域链(the scope chain)。 作用域链上的第一个是最内层的作用域,最后一个是最外层的作用域。
比如:
命名冲突发生在语句 return x * 2
,此时的变量 x 到底是 inside
的参数 x 还是 outside
的变量 x。 分析:此时的作用域链是 {inside, outside, global object},所以 inside
的 x=10
比 outside
的 x=5
的优先级高。 所以是返回 20。
主要参考
Last updated