定义函数
函数声明
function functionName(arg0, arg1, arg2) {
// 函数体
}
函数声明的关键特点是函数声明提升,即函数声明会在代码执行之前获得定义。这意味着函数声明 可以出现在调用它的代码之后
sayHi();
function sayHi() {
console.log("Hi!");
} // 这个例子不会抛出错误,因为 JavaScript 引擎会先读取函数声明,然后再执行代码。
函数表达式
let functionName = function(arg0, arg1, arg2) {
// 函数体
};
函数表达式看起来就像一个普通的变量定义和赋值,即创建一个函数再把它赋值给一个变量 functionName。这样创建的函数叫作匿名函数(anonymous funtion),因为 function 关键字后面没有 标识符。(匿名函数有也时候也被称为兰姆达函数)。未赋值给其他变量的匿名函数的 name 属性是空字 符串。
sayHi(); // Error! function doesn't exist yet
let sayHi = function() {
console.log("Hi!");
}; // 函数表达式跟 JavaScript 中的其他表达式一样,需要先赋值再使用
闭包
闭包是指那些引用另外一个函数作用域中变量的函数
变量对象:全局上下文中的变量,它会在代码执行期间始终存在,
活动对象:函数局部上下文中的变量,只有函数执行期间存在
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
let result = compare(5, 10);
- 在定义compare函数时,就会为它创建作用域链,预装载全局变量对象,并保存在内部的[[Scope]]中,函数的作用域在函数定义的时候就决定了。
- 在调用compare时,会创建相应的上下文,然后通过复制函数的[[Scope]]来创建其作用域链。接着会创建函数的活动对象(用作变量对象)并将其推入作用域链的前端
- AO:活动对象
- 对于每个执行上下文,都有三个重要属性:
- 变量对象(Variable object,VO)
- 作用域链(Scope chain)
- this
- 作用域链:在《JavaScript深入之变量对象》中讲到,当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样由多个执行上下文的变量对象构成的链表就叫做作用域链
在这个例子中,这意味着 compare() 函数执行上下文的作用域链中有两个变量对象:局部变量对象和全局变量对象。作用域链其实是一个包含指针的列表,每个指针分别指向一个变量对象,但物理上并不会包含相应的对象。
函数内部的代码在访问变量时,就会使用给定的名称从作用域链中查找变量。函数执行完毕后,局 部活动对象会被销毁,内存中就只剩下全局作用域。不过,闭包就不一样了。