4.scopeAndFunctionExpress.md

Function Expressions

来看个例子:

1
2
3
4
5
6
7
8
9
10
// 函数定义式
function teacher () {}
// 函数表达式
var myTeacher = function antherTeacher() {
console.log(antherTeacher) // 可以访问到, 因为函数定义也属于本级定义域
}

console.log(teacher) // 函数本身
console.log(myTeacher) // function antherTeacher() {....}
console.log(autherTeacher) // Reference Error

这里要注意两个东西: 函数定义, 函数定义表达式

  1. 函数定义会提升,而函数定义表达式不会提升。
  2. 两者在内存中的不一致, 对于函数定义式, 在编译阶段的收集变量的时候就获得了这个函数在内存中的地址, 而对于函数定义表达式来说, var myTeacher属于LHS, 函数定义属于RHS, 在第二阶段 ,也就是执行阶段再执行的函数定义, 所以, 上面那段代码中,最后一个console会爆出引用错误,因为在编译过程中,js编译器在内存中就找不到antherTeacher了。
1
2
3
4
5
6
7
8
9
// 匿名函数表达式
var a = function() {

}

// 命名函数表达式
var a = function b () {

}

匿名函数更加常见, 但是大胡子建议我们尽可能的使用命名函数表达式.(命名表达式的作用在于, 如果爆出error我们可以获得完整的调用栈, 定位到错误的地方.

named function expression

why we need to alway uses named function expression?

  1. Reliable function self-reference: 命名函数提供了一个可靠的自身引用地址, 这对于递归函数来说很重要.(也就是我们第一章的示例中, 函数内部可以通过命名函数的函数名访问到函数本身, 想一下递归), 任何时候,你要访问函数本身,你都可以通过函数名访问到, 而匿名函数就无法访问到.函数也就更内聚。
  2. More debuggable stack traces: 触发错误后, 错误的调用栈会包含命名函数的信息,而不会有匿名函数的信息.
  3. More self-documenting code: 除去1, 2点不说, 多使用命名函数,对于你的代码来说,更具可读性. 我看函数名就知道咋回事了.OK, 如果你觉得麻烦,那么命名完全可以和你的变量一样,但是前提是你的变量也必须具有可读性。每个函数应该都是有意义的,如果你的函数没有意义,你可能要考虑一下你是否需要这个函数, 你不够理解你的代码,是否要把这个函数在切分成更小的模块?

Arrow function

箭头函数本质上是匿名函数,匿名函数就会有上面说的问题。 所以大胡子并不推荐我们无脑使用箭头函数.

function types hierarchy

(named)function declaration >
named function expression >
anonymous function expression