传统编译语言编译的三个步骤
- 分词/词法分析 (将字符串分解成有意义的代码块(词法单元))
- 解析/语法分析 ((将词法单元流转换成“抽象语法树”(AST))
- 代码生成 (将AST转换为可执行代码)
javascript引擎不会有大量的时间用来进行优化
javascript的编译过程不是发生在构建之前的
引擎(从头到尾负责整个javascript程序的编译以及执行过程)
编译器(负责词法分析以及代码生成)
作用域(负责收集并维护所有声明的标识符组成的一系列查询,确定当前执行的代码对这些标识符的访问权限)
javascript中有两个机制可以“欺骗”词法作用域:eval和with。但是会导致引擎在编译时无法优化,会让代码运行变慢。
最小暴露原则:在软件设计中,应该最小限度地暴露必要内容,而将其他内容都“隐藏起来”。
匿名函数的缺点
- 在栈追踪中不会显示出有意义的函数名,使得调试很困难。
- 如果没有函数名,当函数需要引用自身的时候只能使用已经过期的arguments.callee引用。
- 匿名函数省略了对代码可读性/可理解性很重要的函数名
提升
- 只有声明本身会被提升。而赋值或其他运行逻辑会留在原地。
- 函数声明会被提升,但是函数变大时却不会被提升。
- 当有多个重复的“声明”时,函数提升会优先于变量提升。
闭包
- 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
- 无论通过何种手段将内部函数 传递到所在的词法作用域以外,它都会持有对原始定义作用域的引用,
无论在何处执行这个函数都会使用闭包。
模块模式需要具备的两个必要条件:
- 必须有外部的封闭函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)
- 封闭韩式必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。