函数声明与函数表达式(匿名函数)
函数声明
具有函数名的函数声明,具有如下格式:
function 函数名() {
//code
}
js在初次处理代码时,会全部扫描代码,只查找函数声明。查找到函数声明后函数声明后,定义函数名并将函数的引用传递给函数名。
再次扫描代码,按照顺序执行代码,用到已声明函数时,函数名即调用了函数的引用。
函数表达式
不具有函数名,即匿名函数。为了方便调用,有时将它传递给一个变量(变量存储函数引用),即函数表达式。有时,直接将这个匿名函数传当作实参递给其他函数。如下格式
var a = function () {
//code
}
对于匿名函数,只有在第二次扫描按照顺序执行代码时,才会运行。不会在第一次扫描函数声明时调用。
一等值
在此,我们额外介绍一下js中的一等值概念。在js中把能够实现如下三个功能的称为一等值:
- 将其复制给变量或数组和对象等数据结构中。
- 将其传递给函数。
- 将其从函数中返回。
函数也具有如上全部功能,所以函数也是一等值。
注意:
- 将函数传递给函数,只需要将函数名当作实参即可。若为匿名函数,可以将函数复制给变量进行传递或直接将匿名函数置于实参处。
- 将函数返回可返回,即一般为在函数中声明了另一个函数,将这个声明的函数名返回或直接将匿名函数返回,注意返回函数不要带有括号。
函数嵌套
对于函数嵌套,必须注意函的作用域,对于这点将在闭包中详细介绍。
闭包
概念:指的是函数和引用环境。
什么是引用环境,比如一个函数在定义时,声明的所有 变量和引用的所有变量的值都会随着这个函数一起绑定在一起,我们称之为环境。换句话说,当我们调用这个函数时,函数內的变量在定义时的值会一起被调用。
函数在被调用和返回时,不仅仅是调用和返回了他的函数引用,同时定义函数时函数所包含的其他内容我们打包称为环境一起调用和返回。
接下来我们介绍几个名词:
1. 作用域
我们知道作用域分为全局和局部。位于代码顶层的函数作用域是全局的,而在函数中定义的函数是局部的。
在函数内部,使用函数声明定义一个函数,那在函数内部任何地方都是定义的;使用函数表达式定义一个函数,只有在函数表达式被执行后,才被定义。
2. 词法作用域
词法意味着只需要查看代码结构就可以确定变量的作用域,而不是需要代码执行时才明白。
变量总是在最近的函数作用域內查找值。即使函数内部引用函数中的变量也在最近作用域內查找。
在词法作用域中,重要的是函数是在什么时候定义的,而不是什么时候引用的,在定义时就已经明确结构。因为js是在定义他的环境中执行的。
3. 自由变量
不在本地作用域内定义的变量。
在函数内部中没有直接声明赋值(即不在本地定义的变量),而是调用的变量,我们称为自由变量。在本地定义的变量和所有形参我们称之为局部变量。
4.敲定
可敲定函数的环境指的是给所有自由变量都提供了值的环境。
介绍完上面内容,我们可以重新解释闭包的概念:
闭包:包含自由变量的函数与为所有自由变量提供了变量绑定的环境一起,被称为闭包。
注意:
- 闭包包含的是实际环境而不是环境的副本。当在函数内部自由变量出现后,变量更改赋值,自由变量随之改变。
例子:
var secret = "007";
function getSecret() {
var secret = "008";
function getValue(){
return secret;
}
return getValue;
}
var getValueFun = getSecret();
getValueFun();
结果: 008
return getValue;我们创建了一个闭包,getValue中的secret为一个自由变量,他的环境是getSecret内部,所以值为008;