函数表达式
定义函数的两种方式
函数声明
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)
未完待续……