你不知道的JS 上篇
-
函数作用域和块作用域
- 函数作用域指属于函数的全局变量都可以在整个函数的范围内使用及复用
- 隐藏内部实现,传统函数先声明一个函数,然后在里面添加代码;而反过来,先写一段代码再用函数声明对它进行函数包装,这个代码片段就创建了一个作用域,这就是“隐藏”
- 实现了最小特权的原则(最小授权或最小暴露原则)
- 规避冲突,同名标识符之间的冲突、有了命名空间、模块管理
- 区分函数声明和表达式,看function,关键字出现在声明中的位置,function是声明的第一词,那么是一个函数声明,否则就是函数表达式
- 匿名函数没有名称标识符,函数声明不能省略
- 匿名函数的在栈追踪不会显示有意义的函数名,调试困难
- 调用过期只能用arguments.callee引用
- 可读性不高
- 立即执行函数表达式
- “( )”,包含了函数,成为表达式
- “()()”,IIFE(Immediately Invoked Function Expression),立即执行函数表达式
- 有个用途,倒置代码运行顺序,将需要运行的函数放在第二位,在IIFE执行之后当作参数传递进去
var a = 2; (function IIFE(def){ def(window) })(function def(global){ var a = 3; console.log(a); // 3 console.log(global.a); //2 })
- 块作用域
- 创建的for,if语句里var都是伪装的外部作用域
- with,trh/catch的catch,都会创建一个块作用域
- ES6的"let",声明的变量隐式的了所在的块作用域
- let声明的不会在块作用域中进行提升,声明的代码被运行之前,声明并不“存在”
- 另一个块作用域有利于垃圾收集
- const也是创建块作用域变量,但值是固定的
-
提升
- 先有声明还是先有赋值,编译器会把声明和赋值,在词法分析分开var a = 2,被分为var a 和a = 2
- 只有声明本身会被提升,而赋值或其他运行逻辑会留在原地,每个作用域都会进行提升操作
- 函数声明会被提升,但函数表达式不会被提升,引擎在词法分析时还没有赋值
- 提升的时候,函数声明要优先于变量声明,函数声明也可以覆盖,var声明在前的表达式