函数表达式
定义函数的两种方式
函数声明
function funcName (arg0, arg1, arg2) {}
特点
- 函数声明提升
 
执行代码之前,会先读取函数声明,可以把函数声明放在调用它的语句的后面;
函数表达式
const funcName = function (arg0, arg1, arg2) {// 函数体}
这种形式看起来像是常规的变量赋值语句。即创建一个函数,并将它赋值给变量 funcName
特点
函数既然可以赋值给一个变量,那么其也可以作为一个参数进行传递,也可以作为其他函数的返回值进行返回。
// 作为返回值const getFunctionA = function () {return function () {console.log('functionA')}}// 作为参数const sayFunctonA = function (sayFunctionA) {sayFunctionA()}
注意
函数表达式与其他表达式一样,在使用前,必须赋值;
sayHello();const sayHello = function () {alert('hello')}// 执行结果: 出错
从一个例子看两种方法的区别
需求:根据一个条件判断,来对同一个同名方法进行不同的定义
函数声明这样做
if (condition) {function sayHello () {console.log('吃了吗?')}} else {function sayHello () {alert('吃了再吃点!')}}
- 执行结果:出现某种意想不到的结果,不应如此使用
以上做法,在ECMAScript中属于无效语法
- 大部分浏览器默认返回第第二个函数定义,忽略 condition的值
 - Firefox在condition为true时返回第一个函数定义
 
 
函数表示式这样做
const sayHello;if (condition) {sayHello = function () {console.log('吃了吗?')}} else {sayHello = function () {alert('吃了再吃点!')}}
- 执行结果:不会出任何意外;
 
闭包
定义
指有权访问另一个函数作用域中的变量的函数
创建闭包的常见方式
创建闭包的常见方式,就是在一个函数内部创建另一个函数
function createFunction (propertyName) {return function(object1, object2){let value1 = object1[propertyName] // 内部函数,访问了外部函数的变量let value2 = object2[propertyName] // 内部函数,访问了外部函数的变量if (value1 < value2) {return -1} else if (value1 > value2) {return 0}}}
代码中,注释处,内部函数的代码,访问了外部函数中的变量。即使这个内部函数被返回了,而且在其他的地方调用了,但他仍然可以访问外部函数中的propertyName。之所以还能够访问这个变量,是因为内部函数的作用域链中包含了外部函数的作用域。
为了彻底搞清楚其中的细节,必须从理解函数第一次被调用的时候都会发生什么入手。
某个函数第一次被调用时
- 1.创建执行环境
 - 2.创建对应的作用域链
 - 3.把作用域链赋值给一个特殊的内部属性([Scope])
 - 4.使用 this、arguments 和 其他命名参数的值来初始化函数的活动对象
 
函数执行过程中,为读取和写入变量的值,需要在作用域链中查找变量
例子:
function compare (value1, value2) {if (value1 < value2) {return -1} else if (value1 > value2) {return 1} else {return 0}}let result = compare(5, 10)
未完待续……
